2023-04-20:有一堆石头,用整数数组 stones 表示

其中 stones[i] 表示第 i 块石头的重量。

每一回合,从中选出任意两块石头,然后将它们一起粉碎

假设石头的重量分别为 x 和 y,且 x <= y

那么粉碎的可能结果如下:

如果 x == y,那么两块石头都会被完全粉碎;

如果 x != y,那么重量为 x 的石头将会完全粉碎,而重量为 y 的石头新重量为 y-x。

最后,最多只会剩下一块 石头。

返回此石头 最小的可能重量。

如果没有石头剩下,就返回 0。

答案2023-04-20:

算法流程:

  1. 遍历一遍所有石头,计算石头总重量 sum
  2. 计算目标重量 target = sum / 2
  3. 使用动态规划求解在限制条件下可以得到的最大重量;
  4. 返回石头总重量减去两堆石子的总重量之差,即为最小重量差。

动态规划过程:

  1. 定义状态:设 dp[i][j] 表示前 i 个石头在限制条件下可以得到的最大重量;
  2. 初始化状态:dp[0][j] = 0,表示前 0 个石头在限制条件下无法得到任何重量;dp[i][0] = 0,表示在不限制目标重量的情况下无法得到任何重量;
  3. 状态转移方程:对于第 i 个石头,有两种选择:取或不取。若不取,则当前石头对总重量贡献为0,即 dp[i][j] = dp[i-1][j]。若取,则当前石头会对总重量产生贡献,贡献值为当前石头重量 stones[i-1] 加上前 i-1 个石头在目标重量为 j - stones[i-1] 下可以得到的最大重量 dp[i-1][j-stones[i-1]],即 dp[i][j] = dp[i-1][j-stones[i-1]] + stones[i-1]。因此可以得到状态转移方程:
    dp[i][j] = max(dp[i-1][j], dp[i-1][j-stones[i-1]]+stones[i-1])
  4. 最终结果:返回 sum - 2 * dp[n][target]

其中,max 函数用于计算两个整数中的较大值。

注意:由于题目要求粉碎的重量差最小,因此需要将石头分为两组,使它们的重量之差最小。因此在计算完一组石头的最大重量后,还需要用总重量减去两堆石子的总重量之差,以得到另一组石头的重量。

时间复杂度:该算法使用了动态规划方法,在遍历石头和目标重量的过程中,对于每个子问题都需要计算一次最大重量,因此时间复杂度为 $O(n \times \text{half})$,其中 $n$ 是石头数量,$\text{half}$ 是目标重量的一半。

空间复杂度:在使用动态规划求解最大重量的过程中,需要使用一个二维数组 dp 来保存所有子问题的计算结果。因此空间复杂度为 $O(n \times \text{half})$。但由于每次迭代只需要使用到上一次迭代的结果,因此可以使用滚动数组将空间复杂度优化到 $O(\text{half})$。

go完整代码如下:

package main

import "fmt"

func lastStoneWeightII(stones []int) int {
n := len(stones)
sum := 0
for _, num := range stones {
sum += num
}
half := sum / 2
dp := make([][]int, n+1)
for i := range dp {
dp[i] = make([]int, half+1)
}
for i := n - 1; i >= 0; i-- {
for rest := 0; rest <= half; rest++ {
p1 := dp[i+1][rest]
p2 := 0
if stones[i] <= rest {
p2 = stones[i] + dp[i+1][rest-stones[i]]
}
dp[i][rest] = max(p1, p2)
}
}
return sum - dp[0][half]*2
} func max(x, y int) int {
if x > y {
return x
}
return y
} func main() {
stones := []int{2, 7, 4, 1, 8, 1}
fmt.Println(lastStoneWeightII(stones)) // expected output: 1 stones = []int{31, 26, 33, 21, 40}
fmt.Println(lastStoneWeightII(stones)) // expected output: 5
}

rust代码如下:

fn last_stone_weight_ii(arr: Vec<i32>) -> i32 {
let n = arr.len();
let sum = arr.iter().sum::<i32>();
let half = sum / 2;
let mut dp = vec![vec![0; half as usize + 1]; n + 1];
for i in (0..n).rev() {
for rest in 0..=half {
let p1 = dp[i + 1][rest as usize];
let mut p2 = 0;
if arr[i] <= rest as i32 {
p2 = arr[i] + dp[i + 1][(rest - arr[i]) as usize];
}
dp[i][rest as usize] = p1.max(p2);
}
}
(sum - dp[0][half as usize] * 2) as i32
} fn main() {
let stones = vec![2, 7, 4, 1, 8, 1];
let ans = last_stone_weight_ii(stones);
println!("{}", ans); // 输出 1 let stones = vec![31, 26, 33, 21, 40];
let ans = last_stone_weight_ii(stones);
println!("{}", ans); // 输出 5
}

2023-04-20:有一堆石头,用整数数组 stones 表示 其中 stones[i] 表示第 i 块石头的重量。 每一回合,从中选出任意两块石头,然后将它们一起粉碎 假设石头的重量分别为 x 和的更多相关文章

  1. http://www.cnblogs.com/yycxbjl/archive/2010/04/20/1716689.html

    http://www.cnblogs.com/yycxbjl/archive/2010/04/20/1716689.html PS: 开发工具 VS2010, 所有工程都为Debug状态,本人刚接触 ...

  2. 风口之下,猪都能飞。当今中国股市牛市,真可谓“错过等七年”。 给你一个回顾历史的机会,已知一支股票连续n天的价格走势,以长度为n的整数数组表示,

    转自:http://www.cnblogs.com/ranranblog/p/5845010.html 风口之下,猪都能飞.当今中国股市牛市,真可谓“错过等七年”. 给你一个回顾历史的机会,已知一支股 ...

  3. 给定整数a1、a2、a3、...、an,判断是否可以从中选出若干个数,使得它们的和等于k(k任意给定,且满足-10^8 <= k <= 10^8)。

    给定整数a1.a2.a3.....an,判断是否可以从中选出若干个数,使得它们的和等于k(k任意给定,且满足-10^8 <= k <= 10^8). 分析:此题相对于本节"寻找满 ...

  4. 谷歌面试题:输入是两个整数数组,他们任意两个数的和又可以组成一个数组,求这个和中前k个数怎么做?

    谷歌面试题:输入是两个整数数组,他们任意两个数的和又可以组成一个数组,求这个和中前k个数怎么做? 分析: "假设两个整数数组为A和B,各有N个元素,任意两个数的和组成的数组C有N^2个元素. ...

  5. 给定两个有序整数数组 nums1 和 nums2,将 nums2 合并到 nums1 中,使得 num1 成为一个有序数组

    题目描述: 给定两个有序整数数组 nums1 和 nums2,将 nums2 合并到 nums1 中,使得 num1 成为一个有序数组. 说明:初始化 nums1 和 nums2 的元素数量分别为 m ...

  6. 给一个整数数组,找到两个数使得他们的和等于一个给定的数 target。

    描述 给一个整数数组,找到两个数使得他们的和等于一个给定的数 target. 你需要实现的函数twoSum需要返回这两个数的下标, 并且第一个下标小于第二个下标.注意这里下标的范围是 0 到 n-1. ...

  7. 刷题之给定一个整数数组 nums 和一个目标值 taget,请你在该数组中找出和为目标值的那 两个 整数

    今天下午,看了一会github,想刷个题呢,就翻出来了刷点题提高自己的实际中的解决问题的能力,在面试的过程中,我们发现,其实很多时候,面试官 给我们的题,其实也是有一定的随机性的,所以我们要多刷更多的 ...

  8. 剑指offer23:输入一个整数数组,判断该数组是不是某二叉搜索树的后序遍历的结果。输出Yes OR No。

    1 题目描述 输入一个整数数组,判断该数组是不是某二叉搜索树的后序遍历的结果.如果是则输出Yes,否则输出No.假设输入的数组的任意两个数字都互不相同. 2 思路和方法 二叉搜索树:二叉查找树(Bin ...

  9. 给定一个整数数组 nums 和一个目标值 target,求nums和为target的两个数的下表

    这个是来自力扣上的一道c++算法题目: 给定一个整数数组 nums 和一个目标值 target,请你在该数组中找出和为目标值的那 两个 整数,并返回他们的数组下标. 你可以假设每种输入只会对应一个答案 ...

  10. c语言经典算法——查找一个整数数组中第二大数

    题目: 实现一个函数,查找一个整数数组中第二大数. 算法思想: 设置两个变量max1和max2,用来保存最大数和第二大数,然后将数组剩余的数依次与这两个数比较,如果这个数a比max1大,则先将max1 ...

随机推荐

  1. pycharm2019.3.1版本需要的JetBrains Runtime 11不支持windows 32位系统。

    提示信息显示安装pycharm2019.3.1版本需要的JetBrains Runtime 11不支持windows 32位系统. 2.更换pycharm社区版的安装版本 百度找到解决办法,参考文章& ...

  2. Selenium显式、隐式等待

    显式等待: 显式等待是你在代码中定义等待一定条件发生后再进一步执行你的代码.简单的说就是在指定时间内,一直等待某个条件成立,条件成立后立即执行定位元素的操作:如果超过这个时间条件仍然没有成立,则会抛出 ...

  3. python openpyxl 多个sheet vlookup

    import pandas as pdimport openpyxlfrom openpyxl.styles import Border, Side,colorswb = openpyxl.load_ ...

  4. python学习记录(六)-系统内置模块

    序列化 什么是序列化?序列化是指把python中的数据以文本或二进制形式进行转换,还能反序列化为原来的数据 为什么需要序列化?便于数据在程序与网络之间的传输和存储 json:文本序列化 pickle: ...

  5. 算法学习01—Java底层的正整数与负整数

    算法学习01 - Java 底层的正整数与负整数 本节课学到的知识 编写一个方法,打印出 int 类型数字的二进制长什么样 为什么 int 类型的最大值是 2^32 - 1,最小值是 -2^32 负整 ...

  6. 联想拯救者R9000P风扇拉满加强散热的方法

    管软可以开野兽模式,但是风扇还不是最猛的.锻炼的时候为了保护硬件,牺牲风扇和噪音吧,方法如下:下载 RWEverything运行RW.exe点击笔记本图标+EC文字的图案 修改:B0+0D对应的数据, ...

  7. 9. PEP8规范

    1. 每一级缩进4个空格 2. 续行时缩进要比正常行多缩进, 要能明显看出是续行的 3. 每一行最多79个字符 4. 函数和类定义时在前后加2个空行, 类内接口在定义时, 前后加1个空行 5. 二元运 ...

  8. Pinia使用技巧

    vue2使用的vuex,是一个状态管理器,现在vue3出了最新的pinia,今年偿试一下. 首先是安装,这里要注意一下,有一个持久化插件,如果不用的话,页面一刷新,状态会消失. npm install ...

  9. PHP 错误设置

    错误显示设置 设置:那些错误该显示,以及该如何显示 在PHP中,有两种方式来设置当前脚本的错误处理 1.PHP配置文件--php.ini 修改配合文件需要重启服务 display_error:是否显示 ...

  10. 一个由public关键字引发的bug

    先来看一段代码: @Service @Slf4j public class AopTestService { public String name = "真的吗"; @Retrya ...