程式碼隨想錄演算法訓練營 | 1049. 最後一塊石頭的重量 II,494. 目標和,474.一和零

漪欢酒發表於2024-10-10

1049. 最後一塊石頭的重量 II
題目連結:1049. 最後一塊石頭的重量 II
文件講解︰程式碼隨想錄(programmercarl.com)
影片講解︰最後一塊石頭的重量 II
日期:2024-10-10

想法:這這麼會是分割等和子集一類的問題。。。
Java程式碼如下:

class Solution {
    public int lastStoneWeightII(int[] stones) {
        if(stones == null || stones.length == 0) return 0;
        int sum = 0;
        for(int num : stones) {
            sum += num;
        }
        int target = sum / 2;
        int[] dp = new int[target + 1];

        for(int i = 0; i < stones.length; i++) {
            for(int j = target; j >= stones[i]; j--) {
                dp[j] = Math.max(dp[j], dp[j - stones[i]] + stones[i]);
            }
        }
        return sum - 2 * dp[target];
    }
}

494. 目標和
題目連結:494. 目標和
文件講解︰程式碼隨想錄(programmercarl.com)
影片講解︰目標和
日期:2024-10-10

想法:假設加法的總和為bagSize,那麼減法對應的總和就是sum - bagSize,所以要求的是 bagSize - (sum - bagSize) = target; bagSize = (target + sum) / 2
此時問題就轉化為,用nums裝滿容量為bagSize的揹包,有幾種方法。

  1. dp的意思是有多少種組合滿足,二維陣列dp[i][j]表示nums種0到i的數相加得到j的組合數為dp[i][j],
  2. 遞推公式:第一種情況dp[i - 1][j]表示不加上nums[i]這個數時能得到和為j的組合數,第二種情況要加上nums[i],先就得騰出j - nums[i]的空間,看此時dp[i - 1][j - nums[i]]有多少組合,這個組合數就是加上nums[i]總和為j的組合數。
    3.初始化:初始化第一行第一列,第一行j剛好等於nums[0]時會有1種(要nums[0]),第一列的話如果nums[0]不是0,那麼就1種組合法(不要nums[0]),如果nums[0]是0的話就會麻煩點,那麼就2^1 = 2種組合法(不要nums[0],要nums[0]都行),第一列第二個如果也是0,就會有2^2 = 4種(不要nums[0],要nums[0],不要nums[1],要nums[1]都行),所以有多少個0,就有2多少次方個方法。
    4.遍歷順序:上下左右,左右上下都行。
    5.舉例推導dp陣列

Java程式碼如下:

//二維陣列
class Solution {
    public int findTargetSumWays(int[] nums, int target) {
        int sum = 0;
        for(int num : nums) {
            sum += num;
        }
        if((sum + target) % 2 != 0) return 0;
        if(Math.abs(target) > sum) return 0;
        int bagSize = (sum + target) / 2;

        int[][] dp = new int[nums.length][bagSize + 1];
        int zeroN = 0;
        
        if(nums[0] <= bagSize) dp[0][nums[0]] = 1;
        for(int i = 0; i < nums.length; i++) {
            if(nums[i] == 0) {
                zeroN++;
            }
            dp[i][0] = (int) Math.pow(2, zeroN);
        }

        for(int i = 1; i < nums.length; i++) {
            for(int j = 1; j <= bagSize; j++) {
                if(j >= nums[i]) {
                    dp[i][j] = dp[i - 1][j] + dp[i - 1][j -nums[i]];
                }else {
                    dp[i][j] = dp[i - 1][j];
                }
            }
        }
        return dp[nums.length - 1][bagSize];
    }
}
//一維陣列
class Solution {
    public int findTargetSumWays(int[] nums, int target) {
        int sum = 0;
        for(int num : nums) {
            sum += num;
        }
        if((sum + target) % 2 != 0) return 0;
        if(Math.abs(target) > sum) return 0;
        int bagSize = (sum + target) / 2;

        int[] dp = new int[bagSize + 1];

        dp[0] = 1;

        for(int i = 0; i < nums.length; i++) {
            for(int j = bagSize; j >= nums[i]; j--) {
                dp[j] += dp[j -nums[i]];
            }
        }
        return dp[bagSize];
    }
}

總結:一維陣列的形式初始化只需要dp[0] = 1就行了,想象下nums[0]為0時,j = 0時遞推公式dp[j] += dp[j -nums[i]];依舊可以用,此時相當於dp[0]+dp[0] = 2了。

474.一和零
題目連結:474.一和零
文件講解︰程式碼隨想錄(programmercarl.com)
影片講解︰一和零
日期:2024-10-10

Java程式碼如下:

class Solution {
    public int findMaxForm(String[] strs, int m, int n) {
        int[][] dp = new int[m + 1][n + 1];
        int oneNum, zeroNum;
        for (String str : strs) {
            oneNum = 0;
            zeroNum = 0;
            for (char ch : str.toCharArray()) {
                if (ch == '0') {
                    zeroNum++;
                } else {
                    oneNum++;
                }
            }
            for (int i = m; i >= zeroNum; i--) {
                for (int j = n; j >= oneNum; j--) {
                    dp[i][j] = Math.max(dp[i][j], dp[i - zeroNum][j - oneNum] + 1);
                }
            }
        }
        return dp[m][n];
    }
}

相關文章