2023-04-20:有一堆石头,用整数数组 stones 表示 其中 stones[i] 表示第 i 块石头的重量。 每一回合,从中选出任意两块石头,然后将它们一起粉碎 假设石头的重量分别为 x 和
2023-04-20:有一堆石头,用整数数组 stones 表示
其中 stones[i] 表示第 i 块石头的重量。
每一回合,从中选出任意两块石头,然后将它们一起粉碎
假设石头的重量分别为 x 和 y,且 x <= y
那么粉碎的可能结果如下:
如果 x == y,那么两块石头都会被完全粉碎;
如果 x != y,那么重量为 x 的石头将会完全粉碎,而重量为 y 的石头新重量为 y-x。
最后,最多只会剩下一块 石头。
返回此石头 最小的可能重量。
如果没有石头剩下,就返回 0。
答案2023-04-20:
算法流程:
- 遍历一遍所有石头,计算石头总重量
sum; - 计算目标重量
target = sum / 2; - 使用动态规划求解在限制条件下可以得到的最大重量;
- 返回石头总重量减去两堆石子的总重量之差,即为最小重量差。
动态规划过程:
- 定义状态:设
dp[i][j]表示前i个石头在限制条件下可以得到的最大重量; - 初始化状态:
dp[0][j] = 0,表示前 0 个石头在限制条件下无法得到任何重量;dp[i][0] = 0,表示在不限制目标重量的情况下无法得到任何重量; - 状态转移方程:对于第
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])
- 最终结果:返回
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 和的更多相关文章
- 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状态,本人刚接触 ...
- 风口之下,猪都能飞。当今中国股市牛市,真可谓“错过等七年”。 给你一个回顾历史的机会,已知一支股票连续n天的价格走势,以长度为n的整数数组表示,
转自:http://www.cnblogs.com/ranranblog/p/5845010.html 风口之下,猪都能飞.当今中国股市牛市,真可谓“错过等七年”. 给你一个回顾历史的机会,已知一支股 ...
- 给定整数a1、a2、a3、...、an,判断是否可以从中选出若干个数,使得它们的和等于k(k任意给定,且满足-10^8 <= k <= 10^8)。
给定整数a1.a2.a3.....an,判断是否可以从中选出若干个数,使得它们的和等于k(k任意给定,且满足-10^8 <= k <= 10^8). 分析:此题相对于本节"寻找满 ...
- 谷歌面试题:输入是两个整数数组,他们任意两个数的和又可以组成一个数组,求这个和中前k个数怎么做?
谷歌面试题:输入是两个整数数组,他们任意两个数的和又可以组成一个数组,求这个和中前k个数怎么做? 分析: "假设两个整数数组为A和B,各有N个元素,任意两个数的和组成的数组C有N^2个元素. ...
- 给定两个有序整数数组 nums1 和 nums2,将 nums2 合并到 nums1 中,使得 num1 成为一个有序数组
题目描述: 给定两个有序整数数组 nums1 和 nums2,将 nums2 合并到 nums1 中,使得 num1 成为一个有序数组. 说明:初始化 nums1 和 nums2 的元素数量分别为 m ...
- 给一个整数数组,找到两个数使得他们的和等于一个给定的数 target。
描述 给一个整数数组,找到两个数使得他们的和等于一个给定的数 target. 你需要实现的函数twoSum需要返回这两个数的下标, 并且第一个下标小于第二个下标.注意这里下标的范围是 0 到 n-1. ...
- 刷题之给定一个整数数组 nums 和一个目标值 taget,请你在该数组中找出和为目标值的那 两个 整数
今天下午,看了一会github,想刷个题呢,就翻出来了刷点题提高自己的实际中的解决问题的能力,在面试的过程中,我们发现,其实很多时候,面试官 给我们的题,其实也是有一定的随机性的,所以我们要多刷更多的 ...
- 剑指offer23:输入一个整数数组,判断该数组是不是某二叉搜索树的后序遍历的结果。输出Yes OR No。
1 题目描述 输入一个整数数组,判断该数组是不是某二叉搜索树的后序遍历的结果.如果是则输出Yes,否则输出No.假设输入的数组的任意两个数字都互不相同. 2 思路和方法 二叉搜索树:二叉查找树(Bin ...
- 给定一个整数数组 nums 和一个目标值 target,求nums和为target的两个数的下表
这个是来自力扣上的一道c++算法题目: 给定一个整数数组 nums 和一个目标值 target,请你在该数组中找出和为目标值的那 两个 整数,并返回他们的数组下标. 你可以假设每种输入只会对应一个答案 ...
- c语言经典算法——查找一个整数数组中第二大数
题目: 实现一个函数,查找一个整数数组中第二大数. 算法思想: 设置两个变量max1和max2,用来保存最大数和第二大数,然后将数组剩余的数依次与这两个数比较,如果这个数a比max1大,则先将max1 ...
随机推荐
- selenium 设置时区
driver = webdriver.Chrome() tz_params = {'timezoneId': 'America/New_York'} driver.execute_cdp_cmd('E ...
- Oracle-账户被锁:The account is locked
Oracle-账户被锁:The account is locked cmd-->sqlplus--> 管理员登录:system@ORCL 密码:1 然后输入:alter user kjb( ...
- 关于office 16
word是office的组件之一,Excel也是其中之一. 一用有八大组件.
- Keepalived+HAProxy基于ACL实现单IP多域名负载功能
编译安装 HAProxy 新版 LTS 版本,编译安装 Keepalived 开启HAProxy多线程,线程数与CPU核心数保持一致,并绑定CPU核心 因业务较多避免配置文件误操作,需要按每业务一个配 ...
- SSRF Server-Side Request Forgery(服务器端请求伪造)
什么是SSRF? 犹如其名,SSRF(Server-Side Request Forgery)服务端请求伪造,攻击者可以控制服务器返回的页面,借用服务器的权限访问无权限的页面. 这是一个允许恶意用户导 ...
- Linux0.11源码学习(二)
Linux0.11源码学习(二) linux0.11源码学习笔记 参考资料:https://github.com/sunym1993/flash-linux0.11-talk 源码查看:https:/ ...
- Springboot 结合 Netty 实战聊天系统
音视频技术为什么需要微服务 微服务,英文名:microservice,百度百科上将其定义为:SOA 架构的一种变体.微服务(或微服务架构)是一种将应用程序构造为一组低耦合的服务. 微服务有着一些鲜明的 ...
- 【读书笔记】组合计数中的行列式方法 专题3 完美匹配: the Pfaffian method
目录 专题3-Perfect matchings: the Pfaffian method 一些定义 用2×1的砖密铺a×b的大矩形的方法数 专题3-Perfect matchings: the Pfa ...
- uni-app云开发入门
云函数 首先创建一个uniapp项目,创建项目时选择启用uniCloud云开发. 创建项目成功后,按照下面的步骤进行开发. 创建云函数 1.关联云服务器 2.创建云函数 一个云函数可以看成是一个后 ...
- Chronicle Pro - 一款简单 Mac 理财规划师,管理你的的个人预算
使用Chronicle追踪和支付账单,管理你的个人预算,这是一款简单的Mac理财规划师.获得通知,这样你就不会错过下一个付款截止日期;你再也不用付滞纳金了.把你所有的账单放在一起,计划.检查和分析它们 ...