LeetCode 1049 - 最后一块石头的重量(01背包解法) - 解题思路记录

711 阅读2分钟

Hello, 大家好 好久都没更新算法题目的解题思路了,最近也开始重拾算法。所以要继续更这一块内容了。

今天做的题目的1049,最后的一块石头。具体的题目的内容就不在这边详细说了。大家可以到leetcode官网去看这条题目的描述这边直接上解题的思路

我在刚看到这条题目的时候,我自己也不太懂应该从哪里入手,直到我看到了别人用01背包的解法。我觉得这一题也是可以用此公式直接可以解题出来的

题目简述

Input: stones = [2,7,4,1,8,1] Output: 1 Explanation:
We can combine 2 and 4 to get 2, so the array converts to [2,7,1,8,1] then,
we can combine 7 and 8 to get 1, so the array converts to [2,1,1,1] then,
we can combine 2 and 1 to get 1, so the array converts to [1,1,1] then,
we can combine 1 and 1 to get 0, so the array converts to [1], then that's the optimal value.

题目描述好像很简单,就是输入一个数组,这些数组里面是一些石头的重量。 每次取2个石头。 有2个例子

  1. 例子1. 石头重量x = 石头重量y 的时候 则抵消该重量
  2. 例子2. 石头重量x < 石头重量y 的时候 则取 y-x

这个思路是不是稍微就清晰了一些了? 如果有n块石头,总重量为r 分为2组,每组的重量都是r/2。

那么我们只需要创建1个背包 这个背包的容量 就是 r/2 然后我们看看在r/2的容量下最多能放多少重量的石头。

01背包解法

我们都知道背包有 重量 和 价值 之分。那么在这道题目里面 我们的重量和价值是什么?

其实weight[i]value[i] 都是stones[i] 也就是石头的重量是其重量,也是其价值。

接下来我们把公式套上来

dp[j] = max(dp[j], dp[j-weight[i] + value[i])

这边备注一下 如果不知道 这个公式怎么推导出来的,可以参考这篇文章,我觉得是把01背包问题讲得非常透彻的一篇「代码随想录」帮你把0-1背包学个通透! 强烈推荐大家先阅读这一篇

这个就是我们动态规划用1维数组保存的值。此处的dp[j] 代表容量为j时,能存放dp[j] 的价值

接下来就是写代码的事了~

代码

   func lastStoneWeightII(stones []int) int {
    sum := 0
    target := 0

    for _, v := range(stones) {
        sum += v
    }
    
    target = sum / 2  // 此处会向下取整

    dp := []int{}
    for i:=0; i <= target; i++ {
        dp = append(dp, 0) // 初始化数组为全0先
    }

    for i:= 0; i<len(stones); i++ {
        for j := target; j >= stones[i]; j-- {
            dp[j] = max(dp[j], dp[j-stones[i]] + stones[i])
        }
    }

    return sum - (dp[target] * 2)

    // 整体的思路:
    // 看到题目的时候,其实可以判断为 该题目想把数组中的石头平分为2部分,
    // 例子1. 石头重量x = 石头重量y 的时候 则抵消该重量
    // 例子2. 石头重量x < 石头重量y 的时候 则取 y-x
    // 那就很好办了。 只需要知道背包容量为一半的时候 能装下多少 石头。 再把 总数减去2次一半的值。
    // 就是最后的答案了。 
}

func max (x, y int) int {
    if x > y {
        return x
    }
    return y
}

其实代码也没有特别复杂, 需要几个地方讲解一下的就是 最后那个位置

sum-dp[target] - dp[target]

这里是为什么? 我们都知道 sum 如果是奇数那么 除以2以后得出的肯定是有小数点, 因此这边的target是会向下取整。 比如说sum=15 / 2 = 7.5 这时候 target就是7

因此sum-dp[target] > dp[target]

因此只需要求出 sum - dp[target] * 2 的值就可以了