力扣题解(最后一块石头的重量)

1049. 最后一块石头的重量 II

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

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

  • 如果 x == y,那么两块石头都会被完全粉碎;
  • 如果 x != y,那么重量为 x 的石头将会完全粉碎,而重量为 y 的石头新重量为 y-x

最后,最多只会剩下一块 石头。返回此石头 最小的可能重量 。如果没有石头剩下,就返回 0

思路:

对于本题,需要换一种方式来理解题目。本题实际上就是一些元素取正,一些元素取负,然后加合,要求在结果大于或等于0的情况下最小。因此可以等价成求目标和中存在非零值的正数target。(对于目标和那道题去看上一篇)。

看成每个元素是加上还是减去,标准的01背包问题。

dp[i][j]表示前i个物品,结果恰好是j的所有可能数目。dp[i][j]的构成是:

dp[i-1][j-num[i]],表示加上第i个元素。

dp[i-1][j+num[i]],表示减去第i个元素。

dp[i][j]+=(dp[i-1][j-num[i]]+dp[i-1][j+num[i]]).

注意:本题是存在前面全部是减去一个数的情况,因此j从逻辑上来说可能是负的,但数组的下标只能从0开始,因此需要将逻辑上的(-sum,+sum)转移到实际数组下标(0,2*sum)。则此时要找target就是j=sum+target。

返回值:

j从sum开始,此时dp[n][sum]表示的是加合为0的数目,若为非空则结果是0,不是则j++,一直找到一个sum+k,使得dp[n][sum+k]为非零,则表示和为k是存在的,然后返回k。

class Solution {
public:
    int lastStoneWeightII(vector<int>& stones) {
        int n=stones.size();
      int k=0;
      for(auto e:stones)
      {
        k+=e;
      }
  
      stones.insert(stones.begin(),0);
      vector<vector<int>>dp(n+1,vector<int>(2*k+1,0));

      dp[0][k]=1;
      for(int i=1;i<=n;i++)
      {
        for(int j=0;j<=2*k;j++)
        {
            if(j-stones[i]>=0)
            dp[i][j]+=dp[i-1][j-stones[i]];
            if(j+stones[i]<=2*k)
            dp[i][j]+=dp[i-1][j+stones[i]];
        }
      }

      for(int i=k;i<=2*k;i++)
      {
        if(dp[n][i]!=0)
        return i-k;
      }
      return -1;

    }
};

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值