LeetCode 动态规划专题

120. Triangle – important

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 dp[1010][1010];
    int minimumTotal(vector<vector<int>>& triangle) {
        memset(dp,sizeof dp,0);
        dp[0][0] = triangle[0][0];
        for(int i=1;i<triangle.size();i++)
            dp[i][0] = dp[i-1][0] + triangle[i][0];

        for(int i=1;i<triangle.size();i++)
            for(int j=1;j<triangle[i].size();j++)
                if(i != j)
                    dp[i][j] = min(dp[i-1][j],dp[i-1][j-1]) + triangle[i][j];
                else
                    dp[i][j] =  dp[i-1][j-1] + triangle[i][j];
                    
        int res = 99999999;
        int len = triangle[triangle.size()-1].size();
        for(int j=0;j<len;j++)
            res = min(res,dp[triangle.size()-1][j]);
        return res;
    }
};

这里可以改成从下往上走,同时可以用滚动数组把空间复杂度降到O(N)。

大神的代码 ↓

class Solution {
public:
    int minimumTotal(vector<vector<int>>& triangle) {
        auto &b = triangle.back();
        vector<int> dp(b.size()),f(b.begin(),b.end());
        for(int i=triangle.size()-2;i>=0;i--){
            for(int j=0;j<=i;j++)
                dp[j] = triangle[i][j] + min(f[j] ,f[j+1]);    
            f = dp;
        }
        return f[0];
    }
};

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
  • 思路

正规dp

class Solution {
public:
    long long dp[110][110];
    int uniquePathsWithObstacles(vector<vector<int>>& obstacleGrid) {
        int n = obstacleGrid.size(),m = obstacleGrid[0].size();
        if(obstacleGrid[0][0] == 1) return 0;
        dp[0][0] = !obstacleGrid[0][0];
        for(int i=1;i<m;i++) 
            if(!obstacleGrid[0][i]) dp[0][i] = dp[0][i-1];
            else dp[0][i] = 0;
        for(int i=1;i<n;i++)
            if(!obstacleGrid[i][0]) dp[i][0] = dp[i-1][0];
            else dp[i][0] = 0;

        for(int i=1;i<n;i++)
            for(int j=1;j<m;j++)
                if(!obstacleGrid[i][j]) dp[i][j] = dp[i-1][j] + dp[i][j-1];
                else dp[i][j] =0;
        return dp[n-1][m-1];
    }
};

354. Russian Doll Envelopes – important

You have a number of envelopes with widths and heights given as a pair of integers (w, h). One envelope can fit into another if and only if both the width and height of one envelope is greater than the width and height of the other envelope.

What is the maximum number of envelopes can you Russian doll? (put one inside other)

Note:
Rotation is not allowed.

Example:

Input: [[5,4],[6,4],[6,7],[2,3]]
Output: 3
Explanation: The maximum number of envelopes you can Russian doll is 3 ([2,3] => [5,4] => [6,7]).

  • 思路

无思路,大神解法:
这是最长递增子序列的二维问题。把 w,h 的 2 维递增问题转化为 h 的1维递增问题。 为此要,按照先 w 递增,w 相同时 h 递减的规则排序 排序后,求 h 的 1 维递增时不会重复选择相同的 w(根据排序规则可知 当 i < j 且 w[i]==w[j] 时 h[i] >= h[j] )

然后就是最长递增子序列,dp[i]表示以envelopes[i][1]结尾的字符串最长递增子序列长度。所以初始化所有dp为1,然后当**存在**envelopes[i][1] > envelopes[j][1]时更新dp。

class Solution {
public:
    static bool cmp(vector<int>& a,vector<int>& b){
        if(a[0] == b[0]) return a[1] > b[1];
        return a[0] < b[0];
    } 

    int maxEnvelopes(vector<vector<int>>& envelopes) {
        if(envelopes.size() == 0) return 0;
        sort(envelopes.begin(),envelopes.end(),cmp);
        vector<int> dp(envelopes.size(),1);

        int res = 1;
        for(int i=1;i<envelopes.size();i++){
            for(int j=0;j<i;j++)
                if(envelopes[i][1] > envelopes[j][1])
                    dp[i] = max(dp[i],dp[j] + 1);
            res = max(res,dp[i]);
        }
        return res;
    }
};

338. Counting Bits – important

Given a non negative integer number num. For every numbers i in the range 0 ≤ i ≤ num calculate the number of 1’s in their binary representation and return them as an array.

Example 1:

Input: 2
Output: [0,1,1]
Example 2:

Input: 5
Output: [0,1,1,2,1,2]
Follow up:

It is very easy to come up with a solution with run time O(n*sizeof(integer)). But can you do it in linear time O(n) /possibly in a single pass?
Space complexity should be O(n).
Can you do it like a boss? Do it without using any builtin function like __builtin_popcount in c++ or in any other language.

  • 思路

状态转移函数 ( 真不容易想到 ) :

P(x) = P(x / 2) + (x mod 2)

class Solution {
public:
    vector<int> countBits(int num) {
        vector<int> res(num+1);
        res[0] = 0;
        for(int i=1;i<=num;i++)
            res[i] = res[i >> 1] + (i&1);
        return res;
    }
};

329. Longest Increasing Path in a Matrix – important

Given an integer matrix, find the length of the longest increasing path.

From each cell, you can either move to four directions: left, right, up or down. You may NOT move diagonally or move outside of the boundary (i.e. wrap-around is not allowed).

Example 1:

Input: nums =
[
[9,9,4],
[6,6,8],
[2,1,1]
]
Output: 4
Explanation: The longest increasing path is [1, 2, 6, 9].
Example 2:

Input: nums =
[
[3,4,5],
[3,2,6],
[2,2,1]
]
Output: 4
Explanation: The longest increasing path is [3, 4, 5, 6]. Moving diagonally is not allowed.

  • 思路

之前做过的,大致思想就是DFS+dp保存中间结果

class Solution {
public:
    int dp[1010][1010];
    int n,m;

    int dfs(int x,int y,vector<vector<int>>& mat){
        if(dp[x][y]) return dp[x][y];
        static int X[] = {1,-1,0,0};
        static int Y[] = {0,0,1,-1};

        int res = 0;
        for(int i=0;i<4;i++){
            int newx = x + X[i],newy = y + Y[i], temp = 1;
            if(newx >= 0 && newx < n && newy >= 0 && newy < m)
                if(mat[newx][newy] > mat[x][y])
                    temp = dfs(newx,newy,mat) + 1;
            res = max(res,temp);
        }
        dp[x][y] = res;
        return res;
    }

    int longestIncreasingPath(vector<vector<int>>& matrix) {
        if(matrix.size() == 0) return 0;
        n = matrix.size(), m = matrix[0].size();

        int res = 0;
        for(int i=0;i<n;i++)
            for(int j=0;j<m;j++)
                res = max(res,dfs(i,j,matrix));
        return res;
    }
};

322. Coin Change – important

You are given coins of different denominations and a total amount of money amount. Write a function to compute the fewest number of coins that you need to make up that amount. If that amount of money cannot be made up by any combination of the coins, return -1.

Example 1:

Input: coins = [1, 2, 5], amount = 11
Output: 3
Explanation: 11 = 5 + 5 + 1
Example 2:

Input: coins = [2], amount = 3
Output: -1
Note:
You may assume that you have an infinite number of each kind of coin.

  • 思路

经典的背包问题。

class Solution {
public:
    int coinChange(vector<int>& coins, int amount) {
        sort(coins.begin(),coins.end());

        vector<int> dp(amount+1,99999999);
        dp[0] = 0;
        for(int i=1;i<=amount;i++)
            for(auto &item:coins)
                if(i - item < 0) break;
                else dp[i] = min(dp[i],dp[i - item] + 1);
        return dp[amount] != 99999999?dp[amount]:-1;
    }
};

这样遍历会快一半

class Solution {
public:
    int coinChange(vector<int>& coins, int amount) {
        vector<int> dp(amount+1,99999999);
        dp[0] = 0;
        for(auto &item:coins)
            for(int i=item;i<=amount;i++)
                dp[i] = min(dp[i],dp[i - item] + 1);
        return dp[amount] != 99999999?dp[amount]:-1;
    }
};

221. Maximal Square – important TODO

Given a 2D binary matrix filled with 0’s and 1’s, find the largest square 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: 4

  • 思路

576. Out of Boundary Paths – TODO

There is an m by n grid with a ball. Given the start coordinate (i,j) of the ball, you can move the ball to adjacent cell or cross the grid boundary in four directions (up, down, left, right). However, you can at most move N times. Find out the number of paths to move the ball out of grid boundary. The answer may be very large, return it after mod 109 + 7.

Example 1:

Input: m = 2, n = 2, N = 2, i = 0, j = 0
Output: 6
Explanation:

Example 2:

Input: m = 1, n = 3, N = 3, i = 0, j = 1
Output: 12
Explanation:

Note:

Once you move the ball out of boundary, you cannot move it back.
The length and height of the grid is in range [1,50].
N is in range [0,50].

91. Decode Ways – important

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).

  • 思路

Oh NO !!! 为什么有0。错了好多次。其实0的意义就是不能单独分出来,然后可以合成10分出来!

参考大神的做法,不要直接判断s[i-1]是1还是2,而是将后两位计算出来,直接判断10<temp<26,这样也考虑到0的情况。

class Solution {
public:
    int numDecodings(string s) {
        if(s[0] == '0') return 0;
        vector<int> dp(s.size());
        dp[0] = 1;
        for(int i=1;i<s.size();i++){
            if(s[i] != '0') dp[i] = dp[i-1];
            int temp = (s[i-1]-'0')*10 + s[i]-'0';
            if(10<=temp && temp<=26)
                dp[i] += (i>1)?dp[i-2]:1;
        }
        return dp[s.size()-1];
    }
};

264. Ugly Number II – important

Write a program to find the n-th ugly number.

Ugly numbers are positive numbers whose prime factors only include 2, 3, 5.

Example:

Input: n = 10
Output: 12
Explanation: 1, 2, 3, 4, 5, 6, 8, 9, 10, 12 is the sequence of the first 10 ugly numbers.
Note:

1 is typically treated as an ugly number.
n does not exceed 1690.

  • 思路

评论大神的解法:https://leetcode-cn.com/problems/ugly-number-ii/solution/xiang-xi-tong-su-de-si-lu-fen-xi-duo-jie-fa-by-5-9/

我们知道丑数序列是 1, 2, 3, 4, 5, 6, 8, 9…。

我们所有的丑数都是通过之前的丑数乘以 2, 3, 5 生成的,所以丑数序列可以看成下边的样子。

1, 1×2, 1×3, 2×2, 1×5, 2×3, 2×4, 3×3…。

我们可以把丑数分成三组,用丑数序列分别乘 2, 3, 5 。

乘 2: 1×2, 2×2, 3×2, 4×2, 5×2, 6×2, 8×2,9×2,…
乘 3: 1×3, 2×3, 3×3, 4×3, 5×3, 6×3, 8×3,9×3,…
乘 5: 1×5, 2×5, 3×5, 4×5, 5×5, 6×5, 8×5,9×5,…
我们需要做的就是把上边三组按照顺序合并起来。

合并有序数组的话,可以通过归并排序的思想,利用三个指针,每次找到三组中最小的元素,然后指针后移。

看起来更像考察归并排序

class Solution {
public:
    int nthUglyNumber(int n) {
        int i,j,k;
        i = j = k = 0;
        vector<int> vec{1};
        while(--n){
            int a=2*vec[i],b=3*vec[j],c=5*vec[k];
            int temp = min(a, min(b,c));
            vec.push_back(temp);
            if(a == temp) i++;
            if(b == temp) j++;
            if(c == temp) k++;
        }
        return vec.back();
    }
};

115. Distinct Subsequences – impotant

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).

It’s guaranteed the answer fits on a 32-bit signed integer.

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
^^^

  • 思路

动态规划,si 和 tj 表示前i个s有多少不同子串能够表示前j个t。

这样很容易知道 dp[i][j] = dp[i-1][j]; 大不了不用最后一个字符了!
然后就是当最后的字符相等时,还有一种是用上最后一个字符去匹配,那么需要加上dp[i-1][j-1]

class Solution {
public:
    int numDistinct(string s, string t) {
        vector<vector<long long>> dp(s.size()+1,vector<long long>(t.size()+1));
        for(int i=0;i<s.size();i++)
            dp[i][0] = 1;
        for(int i=1;i<=s.size();i++)
            for(int j=1;j<=t.size();j++){
                dp[i][j] = dp[i-1][j];
                if(s[i-1] == t[j-1]) dp[i][j] += dp[i-1][j-1];
            }
        return dp[s.size()][t.size()];
    }
};

132. Palindrome Partitioning II – TODO

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.

526. Beautiful Arrangement – TODO important

Suppose you have N integers from 1 to N. We define a beautiful arrangement as an array that is constructed by these N numbers successfully if one of the following is true for the ith position (1 <= i <= N) in this array:

The number at the ith position is divisible by i.
i is divisible by the number at the ith position.

Now given N, how many beautiful arrangements can you construct?

Example 1:

Input: 2
Output: 2
Explanation:

The first beautiful arrangement is [1, 2]:

Number at the 1st position (i=1) is 1, and 1 is divisible by i (i=1).

Number at the 2nd position (i=2) is 2, and 2 is divisible by i (i=2).

The second beautiful arrangement is [2, 1]:

Number at the 1st position (i=1) is 2, and 2 is divisible by i (i=1).

Number at the 2nd position (i=2) is 1, and i (i=2) is divisible by 1.

Note:

N is a positive integer and will not exceed 15.

  • 思路

状态压缩dp。

486. Predict the Winner – TODO

Given an array of scores that are non-negative integers. Player 1 picks one of the numbers from either end of the array followed by the player 2 and then player 1 and so on. Each time a player picks a number, that number will not be available for the next player. This continues until all the scores have been chosen. The player with the maximum score wins.

Given an array of scores, predict whether player 1 is the winner. You can assume each player plays to maximize his score.

Example 1:
Input: [1, 5, 2]
Output: False
Explanation: Initially, player 1 can choose between 1 and 2.
If he chooses 2 (or 1), then player 2 can choose from 1 (or 2) and 5. If player 2 chooses 5, then player 1 will be left with 1 (or 2).
So, final score of player 1 is 1 + 2 = 3, and player 2 is 5.
Hence, player 1 will never be the winner and you need to return False.
Example 2:
Input: [1, 5, 233, 7]
Output: True
Explanation: Player 1 first chooses 1. Then player 2 have to choose between 5 and 7. No matter which number player 2 choose, player 1 can choose 233.
Finally, player 1 has more score (234) than player 2 (12), so you need to return True representing player1 can win.
Note:
1 <= length of the array <= 20.
Any scores in the given array are non-negative integers and will not exceed 10,000,000.
If the scores of both players are equal, then player 1 is still the winner.

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值