leetcode-Dynamic Programming(java版本)

背景:本人最近开始刷leetcode,已经按顺序刷完leetcode前200道题目,现在进行二刷,分类进行刷前200道题目,本次分享动态规划(Dynamic Programming),动态规划题目的难度大部分medium难度和hard,题目类型分为一维动态规划和二维动态规划,下面分类进行介绍。

1.一维动态规划

5. Longest Palindromic Substring

Given a string s, find the longest palindromic substring in s. You may assume that the maximum length of s is 1000.

Example 1:

Input: "babad"
Output: "bab"
Note: "aba" is also a valid answer.
Example 2:

Input: "cbbd"
Output: "bb"
class Solution {
    public String longestPalindrome(String s) {
        /*
        * 使用dp思想,从中间向两边扩展。
                复杂度:
                      时间:O(n**2) 空间:O(1)
        * */
        if (s==null || s.length()==0){
            return "";
        }
        int len = 0;
        int start = 0;
        for (int i = 0; i < s.length(); i++) {
            int cur = Math.max(getLength(s,i,i),getLength(s,i,i+1));
            if (cur > len){
                len = cur;
                // 奇数和偶数情况考虑到 case:aba和abba
                start = i - (cur-1)/2;
            }
        }
        return s.substring(start,start+len);
    }

    private int getLength(String s,int l,int r){
        while (l>=0 && r<s.length() &&s.charAt(l)==s.charAt(r)){
                r++;
                l--;
        }
        return (r-l-1);
    }
}

53. Maximum Subarray

Given an integer array nums, find the contiguous subarray (containing at least one number) which has the largest sum and return its sum.

Example:

Input: [-2,1,-3,4,-1,2,1,-5,4],
Output: 6
Explanation: [4,-1,2,1] has the largest sum = 6.
Follow up:

If you have figured out the O(n) solution, try coding another solution using the divide and conquer approach, which is more subtle.
class Solution {
    public int maxSubArray(int[] nums) {
    	// dp[i]表示i位置之前连续子数组的和
        int[] dp = new int[nums.length];
        dp[0] = nums[0];
        int max =dp[0];
        for(int i=1;i<nums.length;i++){
            dp[i] = Math.max(nums[i],dp[i-1]+nums[i]);
            max = Math.max(max,dp[i]);
        }
        return max;
    }
}

70. Climbing Stairs

You are climbing a stair case. It takes n steps to reach to the top.

Each time you can either climb 1 or 2 steps. In how many distinct ways can you climb to the top?

Note: Given n will be a positive integer.

Example 1:

Input: 2
Output: 2
Explanation: There are two ways to climb to the top.
1. 1 step + 1 step
2. 2 steps
Example 2:

Input: 3
Output: 3
Explanation: There are three ways to climb to the top.
3. 1 step + 1 step + 1 step
4. 1 step + 2 steps
5. 2 steps + 1 step
class Solution {
    // public int climbStairs(int n) {
    //     if(n==1){
    //         return 1;
    //     }
    //     if(n==2){
    //         return 2;
    //     }
    //     return climbStairs(n-1)+climbStairs(n-2);
    // }
     public int climbStairs(int n) {
         int[] dp = new int[n+1];
         dp[0] = 1;
         dp[1] = 1;
         for(int i=2;i<=n;i++){
             dp[i] = dp[i-1] + dp[i-2];
         }
         return dp[n];
     }
}

91. Decode Ways

A message containing letters from A-Z is being encoded to numbers using the following mapping:

'A' -> 1
'B' -> 2
...
'Z' -> 26
Given a non-empty string containing only digits, determine the total number of ways to decode it.

Example 1:

Input: "12"
Output: 2
Explanation: It could be decoded as "AB" (1 2) or "L" (12).
Example 2:

Input: "226"
Output: 3
Explanation: It could be decoded as "BZ" (2 26), "VF" (22 6), or "BBF" (2 2 6).
// class Solution {
//     private Map<String,Integer> map;
//     public int numDecodings(String s) {
//         // 给你一个加密的数字字符串,问你一共有多少种不同的解密方式。
//         // 记忆话递归
//         map =new HashMap<String,Integer>();
//         map.put("",1);
//         if(s==null || s.length()==0){
//             return 0;       
//         }
//         return memorized(s);
//     }
//     private int memorized(String s){
//         if(map.containsKey(s)){
//             return map.get(s);
//         }
//         if(s.charAt(0)=='0'){
//             return 0;
//         }
//         if(s.length()==1){
//             return 1;
//         }
//         int w = memorized(s.substring(1));
//         String sub = s.substring(0,2);
//         if(Integer.parseInt(sub)>0&&Integer.parseInt(sub)<=26){
//             w+= memorized(s.substring(2));
//         }
//         map.put(s,w);
//         return w;
//     }
// }
class Solution {
    public int numDecodings(String s) {
        // Dp解法
        if(s==null || s.charAt(0)=='0'){
            return 0;       
        }
        if(s.length()==1){
            return 1;
        }
        int[] dp = new int[s.length()+1];
        dp[0] = 1;
        dp[1] = 1;
        for(int i=1;i<s.length();i++){
            char c1 = s.charAt(i-1);
            char c2 = s.charAt(i);
            if(!isValid(c2)&&(!isValid(c1,c2))){
                return 0;
            }
            if(isValid(c2)){
                dp[i+1] = dp[i];
            }
            if(isValid(c1,c2)){
                dp[i+1] += dp[i-1];
            }
            System.out.println(Arrays.toString(dp));
        }
        return dp[s.length()];
    }
    private boolean isValid(char c){
        return c!='0';
    }
    private boolean isValid(char c1,char c2){
        int num = 10*(c1-'0')+(c2-'0');
        return num>=10&&num<=26;
    }
}

96. Unique Binary Search Trees

Share
Given n, how many structurally unique BST's (binary search trees) that store values 1 ... n?

Example:

Input: 3
Output: 5
Explanation:
Given n = 3, there are a total of 5 unique BST's:

   1         3     3      2      1
    \       /     /      / \      \
     3     2     1      1   3      2
    /     /       \                 \
   2     1         2                 3
class Solution {
    public int numTrees(int n) {
        //         dp[2] =  dp[0] * dp[1]   (1为根的情况,则左子树一定不存在,右子树可以有一个数字)
        //     + dp[1] * dp[0]    (2为根的情况,则左子树可以有一个数字,右子树一定不存在)
        //        同理可写出 n = 3 的计算方法:
        // dp[3] =  dp[0] * dp[2]   (1为根的情况,则左子树一定不存在,右子树可以有两个数字)
        //     + dp[1] * dp[1]    (2为根的情况,则左右子树都可以各有一个数字)
        //       + dp[2] * dp[0]    (3为根的情况,则左子树可以有两个数字,右子树一定不存在)
        int[] dp = new int[n+1];
        dp[0] = 1;
        for(int i=1;i<=n;i++){
            for(int j=0;j<i;j++){
                dp[i] += dp[j]*dp[i-j-1];
            }
        }
        return dp[n];
    }
}

121. Best Time to Buy and Sell Stock

Say you have an array for which the ith element is the price of a given stock on day i.

If you were only permitted to complete at most one transaction (i.e., buy one and sell one share of the stock), design an algorithm to find the maximum profit.

Note that you cannot sell a stock before you buy one.

Example 1:

Input: [7,1,5,3,6,4]
Output: 5
Explanation: Buy on day 2 (price = 1) and sell on day 5 (price = 6), profit = 6-1 = 5.
             Not 7-1 = 6, as selling price needs to be larger than buying price.
Example 2:

Input: [7,6,4,3,1]
Output: 0
Explanation: In this case, no transaction is done, i.e. max profit = 0.
class Solution {
    public int maxProfit(int[] prices) {
        int res = 0;
        if(prices.length<=1){
            return 0;
        }
        int n = prices.length;
        int[] dp = new int[n];
        dp[0] = 0;
        int min = prices[0];
        for(int i=1;i<n;i++){
            dp[i] = Math.max(dp[i-1],prices[i]-min);
            min = Math.min(min,prices[i]);
        }
        return dp[n-1];
    }
}

123. Best Time to Buy and Sell Stock III

Say you have an array for which the ith element is the price of a given stock on day i.

Design an algorithm to find the maximum profit. You may complete at most two transactions.

Note: You may not engage in multiple transactions at the same time (i.e., you must sell the stock before you buy again).

Example 1:

Input: [3,3,5,0,0,3,1,4]
Output: 6
Explanation: Buy on day 4 (price = 0) and sell on day 6 (price = 3), profit = 3-0 = 3.
             Then buy on day 7 (price = 1) and sell on day 8 (price = 4), profit = 4-1 = 3.
Example 2:

Input: [1,2,3,4,5]
Output: 4
Explanation: Buy on day 1 (price = 1) and sell on day 5 (price = 5), profit = 5-1 = 4.
             Note that you cannot buy on day 1, buy on day 2 and sell them later, as you are
             engaging multiple transactions at the same time. You must sell before buying again.
Example 3:

Input: [7,6,4,3,1]
Output: 0
Explanation: In this case, no transaction is done, i.e. max profit = 0.
class Solution {
    public int maxProfit(int[] prices) {
    if(prices.length <= 1) return 0;
    
    int[] left = new int[prices.length];
    int min = prices[0];
    for(int i = 1; i < prices.length; ++i) {
        left[i] = Math.max(left[i-1], prices[i]-min);
        min = Math.min(min, prices[i]);
    }
    
    int[] right = new int[prices.length];
    int max = prices[prices.length-1];
    for(int i = prices.length-2; i >= 0; --i) {
        right[i] = Math.max(right[i+1], max - prices[i]);
        max = Math.max(max, prices[i]);
    }        
    
    int ret = 0;
    for(int i = 0; i < prices.length; ++i) {
        int transaction2 = (i == prices.length-1) ? 0 : right[i+1];
        ret = Math.max(ret, left[i] + transaction2);
    }
    return ret;
}
}

152. Maximum Product Subarray

Given an integer array nums, find the contiguous subarray within an array (containing at least one number) which has the largest product.

Example 1:

Input: [2,3,-2,4]
Output: 6
Explanation: [2,3] has the largest product 6.
Example 2:

Input: [-2,0,-1]
Output: 0
Explanation: The result cannot be 2, because [-2,-1] is not a subarray.
class Solution {
    public int maxProduct(int[] nums) {
        int[] max = new int[nums.length];
        int[] min = new int[nums.length];
        max[0] = nums[0];
        min[0] = nums[0];
        int res = max[0];
        for(int i=1;i<nums.length;i++){
            if(nums[i]>0){
                max[i] = Math.max(nums[i],nums[i]*max[i-1]);
                min[i] = Math.min(nums[i],nums[i]*min[i-1]);
            }else{
                max[i] = Math.max(nums[i],nums[i]*min[i-1]);
                min[i] = Math.min(nums[i],nums[i]*max[i-1]);
            }
            res = Math.max(res,max[i]);
        }
        return res;
    }
}

198. House Robber

You are a professional robber planning to rob houses along a street. Each house has a certain amount of money stashed, the only constraint stopping you from robbing each of them is that adjacent houses have security system connected and it will automatically contact the police if two adjacent houses were broken into on the same night.

Given a list of non-negative integers representing the amount of money of each house, determine the maximum amount of money you can rob tonight without alerting the police.

Example 1:

Input: [1,2,3,1]
Output: 4
Explanation: Rob house 1 (money = 1) and then rob house 3 (money = 3).
             Total amount you can rob = 1 + 3 = 4.
Example 2:

Input: [2,7,9,3,1]
Output: 12
Explanation: Rob house 1 (money = 2), rob house 3 (money = 9) and rob house 5 (money = 1).
             Total amount you can rob = 2 + 9 + 1 = 12.
class Solution {
    // private int[] memory;
    public  int rob(int[] nums) {
    //     /*
    //     * 记忆化递归
    //     * */
    //     memory = new int[nums.length];
    //     Arrays.fill(memory, -1);
    //     return rob(nums,nums.length-1);
    // }
    // private int rob(int[] nums,int i){
    //     if (i<0){
    //         return 0;
    //     }
    //     if (memory[i] >= 0){
    //         return memory[i];
    //     }
    //     return memory[i] = Math.max(rob(nums,i-1),rob(nums,i-2)+nums[i]);
    // }
    //维护一个dp数组,dp[i]代表[0,i]之间最大值,对于i位置来说,有两种选择,抢或者不抢。
        if (nums==null || nums.length==0){
            return 0;
        }
        if (nums.length==1){
            return nums[0];
        }
        if (nums.length==2){
            return Math.max(nums[0],nums[1]);
        }
        int[] dp = new int[nums.length];
        dp[0] = nums[0];
        dp[1] = Math.max(nums[0],nums[1]);
        for (int i = 2; i < nums.length; i++) {
            dp[i] = Math.max(dp[i-1],dp[i-2]+nums[i]);
        }
        return dp[nums.length-1];
    }
}

2.二维动态规划

62. Unique Paths

A robot is located at the top-left corner of a m x n grid (marked 'Start' in the diagram below).

The robot can only move either down or right at any point in time. The robot is trying to reach the bottom-right corner of the grid (marked 'Finish' in the diagram below).

How many possible unique paths are there?

在这里插入图片描述

Example 1:
Input: m = 3, n = 2
Output: 3
Explanation:
From the top-left corner, there are a total of 3 ways to reach the bottom-right corner:
1. Right -> Right -> Down
2. Right -> Down -> Right
3. Down -> Right -> Right
Example 2:
Input: m = 7, n = 3
Output: 28
class Solution {
    public int uniquePaths(int m, int n) {
        if(m<=0||n<=0){
            return 0;
        }
        int[][] dp = new int[m][n];
        dp[0][0] = 1;
        for(int i=1;i<m;i++){
            dp[i][0] = 1;
        }
        for(int j=1;j<n;j++){
            dp[0][j] = 1;
        }
        for(int i=1;i<m;i++){
            for(int j=1;j<n;j++){
                dp[i][j] = dp[i-1][j]+dp[i][j-1];
            }
        }
        return dp[m-1][n-1];
    }
}

63. Unique Paths II

A robot is located at the top-left corner of a m x n grid (marked 'Start' in the diagram below).

The robot can only move either down or right at any point in time. The robot is trying to reach the bottom-right corner of the grid (marked 'Finish' in the diagram below).

Now consider if some obstacles are added to the grids. How many unique paths would there be?

在这里插入图片描述

An obstacle and empty space is marked as 1 and 0 respectively in the grid.

Note: m and n will be at most 100.

Example 1:

Input:
[
  [0,0,0],
  [0,1,0],
  [0,0,0]
]
Output: 2
Explanation:
There is one obstacle in the middle of the 3x3 grid above.
There are two ways to reach the bottom-right corner:
1. Right -> Right -> Down -> Down
2. Down -> Down -> Right -> Right
class Solution {
    public int uniquePathsWithObstacles(int[][] obstacleGrid) {
        int m = obstacleGrid.length;
        int n = obstacleGrid[0].length;
        int[][] dp = new int[m][n];
        for(int i=0;i<m;i++){
            if(obstacleGrid[i][0]==0){
                dp[i][0] = 1;
            }else{
                break;
            }
        }
        for(int j=0;j<n;j++){
            if(obstacleGrid[0][j]==0){
                dp[0][j] = 1;
            }else{
                break;
            }
        }
        for(int i=1;i<m;i++){
            for(int j=1;j<n;j++){
                if(obstacleGrid[i][j]==0){
                    dp[i][j] = dp[i-1][j] + dp[i][j-1];
                }else{
                    dp[i][j] = 0;
                }
            }
        }
        return dp[m-1][n-1];
    }
}

64. Minimum Path Sum

Given a m x n grid filled with non-negative numbers, find a path from top left to bottom right which minimizes the sum of all numbers along its path.

Note: You can only move either down or right at any point in time.

Example:

Input:
[
  [1,3,1],
  [1,5,1],
  [4,2,1]
]
Output: 7
Explanation: Because the path 1→3→1→1→1 minimizes the sum.
class Solution {
    // public int minPathSum(int[][] grid) {
    //     return calculate(grid,0,0);
    // }
    // private int calculate(int[][] grid,int row,int col){
    //     if(row>=grid.length||col>=grid[0].length){
    //         return Integer.MAX_VALUE;
    //     }
    //     if(row==grid.length-1&&col==grid[0].length-1){
    //         return grid[row][col];
    //     }
    //     return grid[row][col] + Math.min(calculate(grid,row+1,col),calculate(grid,row,col+1));
    // }
    public int minPathSum(int[][] grid) {
        //动态规划解法
        int m = grid.length;
        int n = grid[0].length;
        int[][] dp = new int[m][n];
        dp[0][0] = grid[0][0];
        for(int i=1;i<m;i++){
            dp[i][0] = dp[i-1][0]+grid[i][0];
            System.out.println(dp[i][0]);
        }
        for(int j=1;j<n;j++){
            dp[0][j] = dp[0][j-1] + grid[0][j];
            System.out.println(dp[0][j]);
        }
        int i = 1;
        int j = 1;
        while(i<m){
            while(j<n){
             dp[i][j] = Math.min(dp[i-1][j],dp[i][j-1])+grid[i][j];
             System.out.println(dp[i][j]);
             j++;   
            }
            j=1;
            i++;
        }
        return dp[m-1][n-1];
    }
}

72. Edit Distance

Given two words word1 and word2, find the minimum number of operations required to convert word1 to word2.

You have the following 3 operations permitted on a word:

Insert a character
Delete a character
Replace a character
Example 1:

Input: word1 = "horse", word2 = "ros"
Output: 3
Explanation: 
horse -> rorse (replace 'h' with 'r')
rorse -> rose (remove 'r')
rose -> ros (remove 'e')
Example 2:

Input: word1 = "intention", word2 = "execution"
Output: 5
Explanation: 
intention -> inention (remove 't')
inention -> enention (replace 'i' with 'e')
enention -> exention (replace 'n' with 'x')
exention -> exection (replace 'n' with 'c')
exection -> execution (insert 'u')
class Solution {
    public int minDistance(String word1, String word2) {
        int m = word1.length();
        int n = word2.length();
        int[][] dp = new int[m+1][n+1];
        for(int i=0;i<=m;i++){
            dp[i][0]  = i;
        }
        for(int j=0;j<=n;j++){
            dp[0][j] = j;
        }
        for(int i=1;i<=m;i++){
            for(int j=1;j<=n;j++){
                char chi = word1.charAt(i-1);
                char chj = word2.charAt(j-1);
                if(chi==chj){
                    dp[i][j] = dp[i-1][j-1];
                }else{
                    dp[i][j] = 1+Math.min(dp[i-1][j],Math.min(dp[i][j-1],dp[i-1][j-1]));
                }
            }
        }
        return dp[m][n];
    }
}

85. Maximal Rectangle

Given a 2D binary matrix filled with 0's and 1's, find the largest rectangle containing only 1's and return its area.

Example:

Input:
[
  ["1","0","1","0","0"],
  ["1","0","1","1","1"],
  ["1","1","1","1","1"],
  ["1","0","0","1","0"]
]
Output: 6
class Solution {
    public int maximalRectangle(char[][] matrix) {
        int max = 0;
        if(matrix==null || matrix.length==0||matrix[0].length==0){
            return max;
        }
        int row = matrix.length;
        int col = matrix[0].length;
        int[] heights = new int[col];
        for(int i=0;i<row;i++){
            for(int j=0;j<col;j++){
                if(matrix[i][j]=='0'){
                    heights[j]=0;
                }else{
                    heights[j]+=1;
                }
            }
            int area = largestMaximalRectangle(heights);
            max = Math.max(max,area);
        }
        return max;
    }
    private int largestMaximalRectangle(int[] heights){
        int max = 0;
        if(heights==null || heights.length==0){
            return max;
        }
        Stack<Integer> stack = new Stack<>();
        for(int i=0;i<heights.length;i++){
            if(stack.isEmpty()||heights[i]>heights[stack.peek()]){
                stack.push(i);
            }else{
                // 右边界
                int right = i;
                int index =  stack.pop();
                //高度相同向左进行移动
                while(!stack.isEmpty()&&heights[index]==heights[stack.peek()]){
                    index = stack.pop();
                }
                int leftmost = stack.isEmpty() ? -1 : stack.peek();
                max = Math.max(max,(right-leftmost-1)*heights[index]);
                i--;
            }
        }
        // 数组处理完毕
        // 有边界不变
        int rightmost = stack.peek()+1;
        while(!stack.isEmpty()){
            int index = stack.pop();
            int left = stack.isEmpty() ? -1 : stack.peek();
            max = Math.max(max,heights[index]*(rightmost-left-1));
        }
        return max;
    }
}

115. Distinct Subsequences

Given a string S and a string T, count the number of distinct subsequences of S which equals T.

A subsequence of a string is a new string which is formed from the original string by deleting some (can be none) of the characters without disturbing the relative positions of the remaining characters. (ie, "ACE" is a subsequence of "ABCDE" while "AEC" is not).

Example 1:

Input: S = "rabbbit", T = "rabbit"
Output: 3
Explanation:

As shown below, there are 3 ways you can generate "rabbit" from S.
(The caret symbol ^ means the chosen letters)

rabbbit
^^^^ ^^
rabbbit
^^ ^^^^
rabbbit
^^^ ^^^
Example 2:

Input: S = "babgbag", T = "bag"
Output: 5
Explanation:

As shown below, there are 5 ways you can generate "bag" from S.
(The caret symbol ^ means the chosen letters)

babgbag
^^ ^
babgbag
^^    ^
babgbag
^    ^^
babgbag
  ^  ^^
babgbag
    ^^^
class Solution {
    public int numDistinct(String s, String t) {
        // 二维动态规划
        int ls = s.length();
        int lt = t.length();
        int[][] dp = new int[lt+1][ls+1];
        for(int j=0;j<=ls;j++){
            dp[0][j] = 1;
        }
        for(int i=1;i<=lt;i++){
            for(int j=1;j<=ls;j++){
                if(t.charAt(i-1)==s.charAt(j-1)){
                    dp[i][j] = dp[i][j-1]+dp[i-1][j-1];
                }else{
                    dp[i][j] = dp[i][j-1];
                }
            }
        }
        return dp[lt][ls];
    }
}

120. Triangle

Given a triangle, find the minimum path sum from top to bottom. Each step you may move to adjacent numbers on the row below.

For example, given the following triangle

[
     [2],
    [3,4],
   [6,5,7],
  [4,1,8,3]
]
The minimum path sum from top to bottom is 11 (i.e., 2 + 3 + 5 + 1 = 11).

Note:

Bonus point if you are able to do this using only O(n) extra space, where n is the total number of rows in the triangle.
class Solution {
    public int minimumTotal(List<List<Integer>> triangle) {
        //动态规划
        int m = triangle.size();
        int[][] dp = new int[m][m];
        dp[0][0] = triangle.get(0).get(0);
        int res = Integer.MAX_VALUE;
        List<Integer> list0=triangle.get(0);
        if(list0.size()==0){
            return 0;
        }
        if(m==1){
            return list0.get(0);
        }
        for(int i=1;i<m;i++){
            List<Integer> list = triangle.get(i);
            for(int j=0;j<=i;j++){
                if(j==0){
                    dp[i][j] = dp[i-1][j] + list.get(j);
                }else if(j==i){
                    System.out.println(j);
                    dp[i][j] = dp[i-1][j-1] + list.get(j);
                }else{
                    dp[i][j] = Math.min(dp[i-1][j-1],dp[i-1][j]) + list.get(j);
                }
                if(i==(m-1)){
                    res = Math.min(res,dp[i][j]);
                }
            }
        }
        return res;
    }
}

132. Palindrome Partitioning II

Given a string s, partition s such that every substring of the partition is a palindrome.

Return the minimum cuts needed for a palindrome partitioning of s.

Example:

Input: "aab"
Output: 1
Explanation: The palindrome partitioning ["aa","b"] could be produced using 1 cut.
class Solution {
    public int minCut(String s) {
        int n = s.length();
        int[] dp = new int[n];
        Arrays.fill(dp,n);
        boolean[][] valid = new boolean[n][n];
        //初始化回文矩阵
        for(int i=0;i<n;i++){
            valid[i][i] = true;
        }
        for(int l=2;l<=n;l++){
            if(l==2){
               for(int i=0,j=i+l-1;j<n;i++,j++){
                    valid[i][j] = s.charAt(i)==s.charAt(j);
                }
                continue;
            }
            for(int i=0,j=i+l-1;j<n;i++,j++){
                    valid[i][j] = (s.charAt(i)==s.charAt(j) && valid[i+1][j-1]);
            } 
        }
        for(int i=0;i<n;i++){
            if(valid[0][i]){
                dp[i] = 0;
                continue;
            }
            for(int j=0;j<i;j++){
                if(valid[j+1][i]){
                    dp[i] = Math.min(dp[i],dp[j]+1);
                }
            }            
        }
        return dp[n-1];
    }
}

174. Dungeon Game

The demons had captured the princess (P) and imprisoned her in the bottom-right corner of a dungeon. The dungeon consists of M x N rooms laid out in a 2D grid. Our valiant knight (K) was initially positioned in the top-left room and must fight his way through the dungeon to rescue the princess.

The knight has an initial health point represented by a positive integer. If at any point his health point drops to 0 or below, he dies immediately.

Some of the rooms are guarded by demons, so the knight loses health (negative integers) upon entering these rooms; other rooms are either empty (0's) or contain magic orbs that increase the knight's health (positive integers).

In order to reach the princess as quickly as possible, the knight decides to move only rightward or downward in each step.

 

Write a function to determine the knight's minimum initial health so that he is able to rescue the princess.

For example, given the dungeon below, the initial health of the knight must be at least 7 if he follows the optimal path RIGHT-> RIGHT -> DOWN -> DOWN.

在这里插入图片描述

class Solution {
    public int calculateMinimumHP(int[][] dungeon) {
        // 考虑极端情况,只有一个格子。如果格子值val是负数,则英雄血量至少为1-val;如果是整数,则英雄只需要1点血量保证存活即可。
        int m = dungeon.length;
        int n = dungeon[0].length;
        int[][] dp = new int[m+1][n+1];
        for(int i=0;i<=m;i++){
            Arrays.fill(dp[i],Integer.MAX_VALUE);
        }
        dp[m][n-1]=dp[m-1][n] = 1;
        for(int i=m-1;i>=0;i--){
            for(int j=n-1;j>=0;j--){
                dp[i][j] = Math.max(1,Math.min(dp[i][j+1],dp[i+1][j])-dungeon[i][j]);
            }
        }
        return dp[0][0];
    }
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 好的,我来用中文回复这个链接:https://leetcode-cn.com/tag/dynamic-programming/ 这个链接是 LeetCode 上关于动态规划的题目集合。动态规划是一种常用的算法思想,可以用来解决很多实际问题,比如最长公共子序列、背包问题、最短路径等等。在 LeetCode 上,动态规划也是一个非常重要的题型,很多题目都需要用到动态规划的思想来解决。 这个链接里包含了很多关于动态规划的题目,按照难度从简单到困难排列。每个题目都有详细的题目描述、输入输出样例、题目解析和代码实现等内容,非常适合想要学习动态规划算法的人来练习和提高自己的能力。 总之,这个链接是一个非常好的学习动态规划算法的资源,建议大家多多利用。 ### 回答2: 动态规划是一种算法思想,通常用于优化具有重叠子问题和最优子结构性质的问题。由于其成熟的数学理论和强大的实用效果,动态规划在计算机科学、数学、经济学、管理学等领域均有重要应用。 在计算机科学领域,动态规划常用于解决最优化问题,如背包问题、图像处理、语音识别、自然语言处理等。同时,在计算机网络和分布式系统中,动态规划也广泛应用于各种优化算法中,如链路优化、路由算法、网络流量控制等。 对于算法领域的程序员而言,动态规划是一种必要的技能和知识点。在LeetCode这样的程序员平台上,题目分类和标签设置十分细致和方便,方便程序员查找并深入学习不同类型的算法。 LeetCode的动态规划标签下的题目涵盖了各种难度级别和场景的问题。从简单的斐波那契数列、迷宫问题到可以用于实际应用的背包问题、最长公共子序列等,难度不断递进且话题丰富,有助于开发人员掌握动态规划的实际应用技能和抽象思维模式。 因此,深入LeetCode动态规划分类下的题目学习和练习,对于程序员的职业发展和技能提升有着重要的意义。 ### 回答3: 动态规划是一种常见的算法思想,它通过将问题拆分成子问题的方式进行求解。在LeetCode中,动态规划标签涵盖了众多经典和优美的算法问题,例如斐波那契数列、矩阵链乘法、背包问题等。 动态规划的核心思想是“记忆化搜索”,即将中间状态保存下来,避免重复计算。通常情况下,我们会使用一张二维表来记录状态转移过程中的中间值,例如动态规划求解斐波那契数列问题时,就可以定义一个二维数组f[i][j],代表第i项斐波那契数列中,第j个元素的值。 在LeetCode中,动态规划标签下有众多难度不同的问题。例如,经典的“爬楼梯”问题,要求我们计算到n级楼梯的方案数。这个问题的解法非常简单,只需要维护一个长度为n的数组,记录到达每一级楼梯的方案数即可。类似的问题还有“零钱兑换”、“乘积最大子数组”、“通配符匹配”等,它们都采用了类似的动态规划思想,通过拆分问题、保存中间状态来求解问题。 需要注意的是,动态规划算法并不是万能的,它虽然可以处理众多经典问题,但在某些场景下并不适用。例如,某些问题的状态转移过程比较复杂,或者状态转移方程中存在多个参数,这些情况下使用动态规划算法可能会变得比较麻烦。此外,动态规划算法也存在一些常见误区,例如错用贪心思想、未考虑边界情况等。 总之,掌握动态规划算法对于LeetCode的学习和解题都非常重要。除了刷题以外,我们还可以通过阅读经典的动态规划书籍,例如《算法竞赛进阶指南》、《算法与数据结构基础》等,来深入理解这种算法思想。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值