Home
  • 计算机网络
  • 操作系统
  • 数据结构与算法
  • 设计模式
  • JavaSE
  • JVM
  • JUC
  • Netty
  • CPP
  • QT
  • UE
  • Go
  • Gin
  • Gorm
  • HTML
  • CSS
  • JavaScript
  • vue2
  • TypeScript
  • vue3
  • react
  • Spring
  • SpringMVC
  • Mybatis
  • SpringBoot
  • SpringSecurity
  • SpringCloud
  • Mysql
  • Redis
  • 消息中间件
  • RPC
  • 分布式锁
  • 分布式事务
  • 个人博客
  • 弹幕视频平台
  • API网关
  • 售票系统
  • 消息推送平台
  • SaaS短链接系统
  • Linux
  • Docker
  • Git
GitHub (opens new window)
Home
  • 计算机网络
  • 操作系统
  • 数据结构与算法
  • 设计模式
  • JavaSE
  • JVM
  • JUC
  • Netty
  • CPP
  • QT
  • UE
  • Go
  • Gin
  • Gorm
  • HTML
  • CSS
  • JavaScript
  • vue2
  • TypeScript
  • vue3
  • react
  • Spring
  • SpringMVC
  • Mybatis
  • SpringBoot
  • SpringSecurity
  • SpringCloud
  • Mysql
  • Redis
  • 消息中间件
  • RPC
  • 分布式锁
  • 分布式事务
  • 个人博客
  • 弹幕视频平台
  • API网关
  • 售票系统
  • 消息推送平台
  • SaaS短链接系统
  • Linux
  • Docker
  • Git
GitHub (opens new window)
  • 哈希表

  • 双指针

  • 数组

  • 字符串

  • 链表

  • 树

  • 回溯

  • 动态规划

    • 典型问题—斐波那契类型
    • 典型dp—背包问题
    • 典型dp—子序列问题
    • 典型dp—股票问题
    • 线性dp
      • 198. 打家劫舍
      • 213. 打家劫舍 II
      • 子数组问题
        • 53. 最大子数组和
        • 152. 乘积最大子数组
        • 2321. 拼接数组的最大分数
        • 2771. 构造最长非递减子数组
        • 1186. 删除一次得到子数组最大和
      • 118. 杨辉三角
      • 45. 跳跃游戏 II
      • 55. 跳跃游戏
      • 91. 解码方法
      • 650. 只有两个键的键盘
      • 552. 学生出勤记录 II
      • 403. 青蛙过河
      • 343. 整数拆分
      • 1262. 可被三整除的最大和
      • 983. 最低票价
      • 2786. 访问数组中的位置使分数最大
      • 2312. 卖木头块
      • 2320. 统计放置房子的方式数
      • 2380. 二进制字符串重新安排顺序需要的时间
      • 2830. 销售利润最大化
      • 2611. 老鼠和奶酪
    • 区间dp
    • 树形dp
    • 状压dp
    • 数位dp
    • 多维dp
  • 图

  • 二分查找

  • 贪心

  • 栈&队列

  • 堆

  • 位运算

  • 数据结构设计

  • rui的精选题单

  • 笔试真题

  • LeetCode周赛

  • ACM模式输入输出
  • 数学

  • 数据结构与算法
  • 动态规划
Nreal
2023-11-17
目录

线性dp

# 198. 打家劫舍 (opens new window)

方法一:记忆化搜索

class Solution {
    int[] memo;
    int[] nums;
    public int rob(int[] nums) {
        int n = nums.length;
        this.nums = nums;
        this.memo = new int[n];
        Arrays.fill(memo,-1);
        return dfs(0);
    }
    int dfs(int i){
        if(i>=nums.length){
            return 0;
        }
        if(memo[i]!=-1){
            return memo[i];
        }
        return memo[i] = Math.max(dfs(i+1),dfs(i+2)+nums[i]);
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20

方法二:动态规划

class Solution {
    public int rob(int[] nums) {
        int n = nums.length;
        int[] dp = new int[n+2];
        for(int i=0;i<n;i++){
            dp[i+2] = Math.max(dp[i+1],dp[i]+nums[i]);
        }
        return dp[n+1];
    }
}
1
2
3
4
5
6
7
8
9
10

优化;

class Solution {
    public int rob(int[] nums) {
        int d0=0,d1=0;
        for(int x:nums){
            int tmp = Math.max(d1,d0+x);
            d0 = d1;
            d1 = tmp;
        }
        return d1;
    }
}
1
2
3
4
5
6
7
8
9
10
11

# 213. 打家劫舍 II (opens new window)

class Solution {
    int[] nums;
    public int rob(int[] nums) {
        this.nums = nums;
        int n = nums.length;
        return Math.max(nums[0]+dfs(2,n-1),dfs(1,n));
    }
    int dfs(int l,int r){
        int d0=0,d1=0;
        for(int i=l;i<r;i++){
            int tmp = Math.max(d0+nums[i],d1);
            d0 = d1;
            d1 = tmp;
        }
        return d1;
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

# 子数组问题

# 53. 最大子数组和 (opens new window)

方法一:记忆化搜索

class Solution {
    int[] nums;
    int[] memo;
    public int maxSubArray(int[] nums) {
        int n = nums.length;
        this.nums = nums;
        this.memo = new int[n];
        int ret = nums[0];
        for(int i=1;i<n;i++){
            ret = Math.max(ret,dfs(i));
        }
        return ret;
    }
    int dfs(int i){
        if(i<0) return 0;
        if(memo[i]!=0) return memo[i];
        return memo[i] = Math.max(dfs(i-1)+nums[i],nums[i]);
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19

方法二:动态规划

状态定义:以nums[i]结尾的连续子数组的最大和;

class Solution {
    public int maxSubArray(int[] nums) {
        int n = nums.length;
        int[] dp = new int[n];
        dp[0] = nums[0];
        for(int i=1;i<n;i++){
            if(dp[i-1]>0)
                dp[i] = dp[i-1]+nums[i];
            else
                dp[i] = nums[i];
        }
        int res = dp[0];
        for(int i=1;i<n;i++){
            res = Math.max(res,dp[i]);
        }
        return res;
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

# 152. 乘积最大子数组 (opens new window)

class Solution {
    public int maxProduct(int[] nums) {
        int n = nums.length;
        if(n==0)
            return 0;
        int[] maxDp = new int[n];
        int[] minDp = new int[n];
        maxDp[0] = nums[0];
        minDp[0] = nums[0];
        for(int i=1;i<n;i++){
            if(nums[i]>=0){
                maxDp[i] = Math.max(nums[i],maxDp[i-1]*nums[i]);
                minDp[i] = Math.min(nums[i],minDp[i-1]*nums[i]);
            }else{
                maxDp[i] = Math.max(nums[i],minDp[i-1]*nums[i]);
                minDp[i] = Math.min(nums[i],maxDp[i-1]*nums[i]);
            }
        }
        int ret = maxDp[0];
        for(int i=1;i<n;i++){
            ret = Math.max(ret,maxDp[i]);
        }
        return ret;
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25

# 2321. 拼接数组的最大分数 (opens new window)

# 2771. 构造最长非递减子数组 (opens new window)

# 1186. 删除一次得到子数组最大和 (opens new window)

# 118. 杨辉三角 (opens new window)

class Solution {
    public List<List<Integer>> generate(int numRows) {
        List<List<Integer>> ret = new ArrayList<>();
        for(int i=0;i<numRows;i++){
            List<Integer> row = new ArrayList<>();
            for(int j=0;j<=i;j++){
                if(j==0 || j==i){
                    row.add(1);
                }else{
                    row.add(ret.get(i-1).get(j-1) + ret.get(i-1).get(j));
                }
            }
            ret.add(row);
        }
        return ret;
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

# 45. 跳跃游戏 II (opens new window)

class Solution {
    public int jump(int[] nums) {
        int n = nums.length;
        int[] dp = new int[n];
        Arrays.fill(dp,Integer.MAX_VALUE/2);
        dp[0] = 0;
        for(int i=1;i<n;i++){
            for(int j=0;j<i;j++){
                if(i-j<=nums[j]){
                    dp[i] = Math.min(dp[j]+1,dp[i]);
                }
            }
        }
        return dp[n-1];
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

# 55. 跳跃游戏 (opens new window)

class Solution {
    public boolean canJump(int[] nums) {
        int n = nums.length;
        boolean[] dp = new boolean[n];
        dp[0] = true;
        for(int i=1;i<n;i++){
            for(int j=0;j<i;j++){
                if(dp[j] && (i-j)<=nums[j]){
                    dp[i] = true;
                    break;
                }
            }
        }
        return dp[n-1];
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

不同定义:

class Solution {
    public boolean canJump(int[] nums) {
        int n = nums.length;
        if(n==1)
            return true;
        if(nums[0]==0)
            return false;
        // i点之前能跳的最远距离
        int[] dp = new int[n];
        dp[0] = nums[0];
        for(int i=1;i<n-1;i++){
            dp[i] = Math.max(dp[i-1],nums[i]+i);
            if(dp[i]>=n-1)
                return true;
            if(dp[i]==i)
                return false;
        }
        return true;
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20

# 91. 解码方法 (opens new window)

# 650. 只有两个键的键盘 (opens new window)

# 552. 学生出勤记录 II (opens new window)

# 403. 青蛙过河 (opens new window)

# 343. 整数拆分 (opens new window)

class Solution {
    public int integerBreak(int n) {
        int[] dp = new int[n+1];//长度为i的绳子减为m段最大乘积
        dp[1] = 1;
        for(int i=2;i<=n;i++){
            for(int j=1;j<i;j++){
                // 前j段剪或不剪
                dp[i] = Math.max(dp[i],Math.max(dp[j]*(i-j),j*(i-j)));
            }
        }
        return dp[n];
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13

# 1262. 可被三整除的最大和 (opens new window)

记忆化搜索:

class Solution {
    int[][] memo;
    int[] nums;
    public int maxSumDivThree(int[] nums) {
        int n = nums.length;
        this.nums = nums;
        this.memo = new int[n][3];
        for(int[] row:memo){
            Arrays.fill(row,-1);
        }
        return dfs(n-1,0);
    }
    int dfs(int i,int j){
        if(i<0){
            return j==0?0:Integer.MIN_VALUE;
        }
        if(memo[i][j]!=-1){
            return memo[i][j];
        }
        return memo[i][j] = Math.max(dfs(i-1,j),dfs(i-1,(j+nums[i])%3)+nums[i]);
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22

# 983. 最低票价 (opens new window)

# 2786. 访问数组中的位置使分数最大 (opens new window)

# 2312. 卖木头块 (opens new window)

# 2320. 统计放置房子的方式数 (opens new window)

# 2380. 二进制字符串重新安排顺序需要的时间 (opens new window)

# 2830. 销售利润最大化 (opens new window)

# 2611. 老鼠和奶酪 (opens new window)

典型dp—股票问题
区间dp

← 典型dp—股票问题 区间dp→

Theme by Vdoing | Copyright © 2021-2024
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式