题目描述:
有一堆石头,每块石头的重量都是正整数。
每一回合,从中选出任意两块石头,然后将它们一起粉碎。假设石头的重量分别为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]
,这就是最优值。
提示:
1 <= stones.length <= 30
1 <= stones[i] <= 1000
解题思路
求两个集合(将stones
分割成两个集合)的最小差值;
1)、求所有的stones
的和 sum
;
2)、求最接近sum / 2
的集合的和为 ret
;另外一个集合的和为 sum - ret
;
要求的结果就是: abs(sum - ret - ret)
;
代码实现:
class Solution {
public:
int lastStoneWeightII(vector<int>& stones) {
int sum = 0 ;
for (int tmp : stones)
sum += tmp ;
int ans = sum >> 1 ;
int i , j ;
vector<bool> inkNote(ans + 1 , false) ;
inkNote[0] = true ;
//动态规划的思想
for (i = 0 ; i < stones.size() ; i ++)
{
for (j = ans - stones[i] ; j > -1 ; j --)
{
if (inkNote[j])
inkNote[j + stones[i]] = true ;
}
}
int ret = 0 ;
for(i = 0 ; i <= ans ; i ++)
if (inkNote[i]) ret = i ;
cout << ans << endl ;
return sum - (ret << 1) ;
}
};
复杂度:
时间复杂度:O(n * sum(stones[i])) i < stones.size()
;
空间复杂度:O(sum(stones[i])) i < stones.size()
;