最后一块石头的重量 II

有一堆石头,用整数数组 stones 表示。其中 stones[i] 表示第 i 块石头的重量。

每一回合,从中选出任意两块石头,然后将它们一起粉碎。假设石头的重量分别为 x 和 y,且 x <= y。那么粉碎的可能结果如下:

如果 x == y,那么两块石头都会被完全粉碎;
如果 x != y,那么重量为 x 的石头将会完全粉碎,而重量为 y 的石头新重量为 y-x。
最后,最多只会剩下一块 石头。返回此石头 最小的可能重量 。如果没有石头剩下,就返回 0。

示例 1:

输入:stones = [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],这就是最优值。

示例 2:

输入:stones = [31,26,33,21,40]
输出:5

示例 3:

输入:stones = [1,2]
输出:1

错误解法

​ 每次都将最大和次大的石头进行消除,此目的在于每次都将最大的石头消除。解法为:每次循环之前先将数组进行从小到大排序,然后取最大和次大的相减,将得到的值重新放入到数组中,并且将最大和次大的值从数组中删除。直到数组的长度等于1或者零,结束循环。

func lastStoneWeightII(stones []int) int {
	if len(stones)==0 {
		return 0
	}

	if len(stones)==1{
		return stones[0]
	}
	sort.Ints(stones)
	a := len(stones)-1
	b := a - 1
	tmp := 0
	tmp = stones[a] -stones[b]
	if tmp!=0{
		stones = stones[:len(stones)-2]
		stones = append(stones,tmp)
	}
	return lastStoneWeightII(stones)
}

结果错误:一种情况是,当出现两个最大的时候,然后其他的又比较靠近的时候,这种解法就会出现错误。

正确解法

​ 从计算表达式上看,结合减数和被减数,只要这两个值相减的结果越小越好。假设减数为n,则被减数为sum-n。因此所求的结果为:sum-2n。因此我们只要求出n越接近sum/2越好。对于从一堆数组中求出越接近n的问题跟01背包问题的解法一样。

dp[i]/[j]表示前i个数能凑成和不超过j的最大值。每个物品都有选和不选的两种决策。对于前i(从1开始)个物品来说,如果stones[i-1]>j的话,此时的dp[i]/[j] = dp[i-1]/[j],即不选。如果前i个物品,如果stones[i-1] <= j,此时可以选和可以不选,我们只要这两个决策中的最大值:dp[i]/[j] = max(dp[i-1]/[j],dp[i-1]/[j-stons[i-1]]+stones[i-1])。

代码实现:

package main

import (
	"log"
)

func lastStoneWeightII(stones []int) int {
	sum :=0
	for i:=0;i<len(stones);i++{
		sum += stones[i]
	}
	sum2 := sum / 2
	dp := make([][]int,len(stones)+1)
	for i:=0;i<len(dp);i++{
		dp[i] = make([]int,sum2+1)
	}
	n := len(stones)
	for i:=1;i<=n;i++{
		for j:=0;j<=sum2;j++{
				if j<stones[i-1]{
				dp[i][j] = dp[i-1][j]
				}else if j>=stones[i-1] {
					// 这里有点迷惑:为什么是取最大值呢
					dp[i][j] = max(dp[i-1][j],dp[i-1][j-stones[i-1]] + stones[i-1])
				}
		}
	}
	return sum - 2 * dp[n][sum2]
}

func max(a,b int)int{
	if a>b{
		return a
	}
	return b
}

func main(){
	log.Println(lastStoneWeightII([]int{31,26,33,21,40}))
}

posted @ 2021-06-08 14:02  Myuniverse  阅读(109)  评论(0编辑  收藏  举报