本周算法总结

1.不同路径2

public class DifferentPath2 {
    public static void main(String[] args) {
        System.out.println(uniquePathsWithObstacles(new int[][] {{0,0,0},{0,1,0},{0,0,0}}));
    }
    public static int uniquePathsWithObstacles(int[][] obstacleGrid) {
        int n = obstacleGrid.length;
        int m = obstacleGrid[0].length;
        int[] dp = new int[m];
        //起点可能有障碍物
        dp[0] = (obstacleGrid[0][0] == 1) ? 0 : 1;
        for(int i = 0; i < n; ++i) {
            for(int j = 0; j < m; ++j) {
                //有障碍物的格子直接赋0
                if(obstacleGrid[i][j] == 1) {
                    dp[j] = 0;
                }
                //否则dp[j]的值由左方和上一次迭代的dp[j]累加而来
                else if(obstacleGrid[i][j] == 0 && j - 1 >= 0) {
                    dp[j] = dp[j] + dp[j - 1];
                }
            }
        }
        return dp[m - 1];
    }

2.整数拆分

public class IntegerSplitting {
    public static void main(String[] args) {
        System.out.println(integerBreak(2));
    }
    public static int integerBreak(int n) {
        if(n <= 3) return n - 1;
        int a = n / 3, b = n % 3;
        if(b == 0) return (int)Math.pow(3, a);
        if(b == 1) return (int)Math.pow(3, a - 1) * 4;
        return (int)Math.pow(3, a) * 2;
    }

}

3.最长奇偶数组

public class LongestOddEvenGroup {
    public static void main(String[] args) {
        System.out.println(longestAlternatingSubarray(new int[] {3,2,5,4},5));
    }
    public static int longestAlternatingSubarray(int[] nums, int threshold) {
        int n = nums.length;
        int ans = 0, i = 0;
        while (i < n) {
            if (nums[i] > threshold || nums[i] % 2 != 0) {
                i++; // 直接跳过
                continue;
            }
            int start = i; // 记录这一组的开始位置
            i++; // 开始位置已经满足要求,从下一个位置开始判断
            while (i < n && nums[i] <= threshold && nums[i] % 2 != nums[i - 1] % 2) {
                i++;
            }
            // 从 start 到 i-1 是满足题目要求的(并且无法再延长的)子数组
            ans = Math.max(ans, i - start);
        }
        return ans;
    }
}

4.分割等和子集

public class DivideEqualSumSubsets {
    public static void main(String[] args) {
        System.out.println(canPartition(new int[]{1, 5, 11, 5}));
    }
    public static boolean canPartition(int[] nums) {
        int sum = 0, maxNum = 0;
        for (int num : nums) {
            sum += num;
            maxNum = Math.max(maxNum, num);
        }
        if (sum % 2 != 0 || maxNum * 2 > sum) {
            return false;
        }
        int n = nums.length;
        int target = sum / 2;
        boolean[] dp = new boolean[target + 1];
        dp[0] = true;
        for (int i = 1; i <= n; i++) {
            for (int j = target; j >= nums[i - 1]; j--) {
                dp[j] |= dp[j - nums[i - 1]];
            }
        }
        return dp[target];
    }
}

5.最后一块石头的重量2

public class TheWeightOfTheLastStone2 {
    public static void main(String[] args) {
        System.out.println(lastStoneWeightII(new int[]{2, 7, 4, 1, 8, 1}));
    }
    public static int lastStoneWeightII(int[] stones) {
        if (stones == null || stones.length <= 0) {
            return 0;
        }

        int sum = 0;
        for (int stone : stones) {
            sum += stone;
        }
        // 根据推导,当石头最小可能重量时,最好子集数组石头的总重量,趋近于 且 最大为 sum / 2
        int maxWeight = sum / 2;
        int length = stones.length;
        boolean[] dp = new boolean[maxWeight + 1];  // dp[i] 表示,是否有子集数组,重量和为i
        dp[0] = true;
        for (int stone : stones) {
            for (int i = maxWeight; i >= stone; i--) {
                dp[i] = dp[i] || dp[i - stone];
            }
        }

        // 从 最大值 开始,遍历dp数组,寻找最大i的值
        for (int i = maxWeight; ; i--) {
            if (dp[i]) {
                return sum - 2 * i; // 根据数学推导,计算result
            }
        }
    }
}

 结束。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值