执行用时:16 ms, 在所有 Python 提交中击败了100.00%的用户
内存消耗:13 MB, 在所有 Python 提交中击败了74.16%的用户
题目
有一堆石头,每块石头的重量都是正整数。
每一回合,从中选出任意两块石头,然后将它们一起粉碎。假设石头的重量分别为 x 和 y,且 x <= y。那么粉碎的可能结果如下:
如果 x == y,那么两块石头都会被完全粉碎;
如果 x != y,那么重量为 x 的石头将会完全粉碎,而重量为 y 的石头新重量为 y-x。
最后,最多只会剩下一块石头。返回此石头最小的可能重量。如果没有石头剩下,就返回 0。
示例:
输入:[2,7,4,1,8,1]
输出:1
解释:
组合 2 和 4,得到 2,所以数组转化为 [2,7,1,8,1],
组合 7 和 8,得到 1,所以数组转化为 [2,1,1,1],
组合 2 和 1,得到 1,所以数组转化为 [1,1,1],
组合 1 和 1,得到 0,所以数组转化为 [1],这就是最优值。
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/last-stone-weight-ii
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
解题思路
题目分析
两个石头,两两相减,最后剩下一个最小值。有点消消乐的意思。。。
1.石头的重量都是整数
2.石头可以完全消除
3.可以两个石头消除一个石头。即1-n,n-n,n-1进行消除
在不理解题目本质的情况下只能用搜索的模式取解决
为了更好的理解和解决问题,我们把问题抽象成数学问题
有N个石头A,B,C,D,E。。。
A可和B消除,也可以不消除
我们假设最优情况是
1.A - (B-C) - (D-E)…
2.A - B - C - D - E…
3.B - A - (C - D - E)…
通过上面的假设,很容易发现
其实题目的数学模型非常简单
就是ABCDE石头前面可以正负两种情况,求最后的和最小
即把石头分成两堆,尽量分的更均匀,两堆的差值最小
解题思路
那有没有办法在遍历一次石头的情况下 解决这个问题呢?
我们反过来思考 ,如果要在遍历一次石头的情况下,我们需要什么
1.我们要能记录下来石头两种情况的累加状态(正,负状态)
2.找到最接近 石头总和/2 的记录
首先解决第一个问题,我们找出小于等于 石头总和/2 的那堆石头
我们遍历石头堆
第一个石头A 出现两状态(加|不加) 记为A(2)
第二个石头B 出现两状态(加|不加) 记为B(4) = A(2) * 2
第三个石头C 出现两状态(加|不加) 记为C(8) = B(2) * 2
。
第n个石头N 出现两状态(加|不加) 记为N(2^n)
我们可以用一个字典,把2^n种情况的不同结果全部记录下来
然后找到最接近 石头总和/2 的结果
这样就做到了在遍历一次石头堆的情况下,找到最佳结果
优化:用字典保存每次的状态比较复杂,可以使用位运算来完成 更简单方便
record = (record | record << i)
就能记录每次状态的叠加结果
代码
class Solution(object):
def lastStoneWeightII(self, stones):
"""
:type stones: List[int]
:rtype: int
"""
if len(stones) == 1:
return stones[0]
sum_all = sum(stones)
half = sum_all // 2
record = 1
for i in stones:
record = (record | record << i)
record = bin(record)[-half-1:]
less_stones = len(record) - record.find('1') - 1
return sum_all - less_stones - less_stones
作者:liye-5u
链接:https://leetcode-cn.com/problems/last-stone-weight-ii/solution/1049-zui-hou-yi-kuai-shi-tou-de-zhong-li-2irn/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。/