interview_dp

63. 不同路径 II

class Solution:
    def uniquePathsWithObstacles1(self, obstacleGrid: List[List[int]]) -> int:
        m, n = len(obstacleGrid), len(obstacleGrid[0])
        if obstacleGrid[0][0] == 1 or obstacleGrid[-1][-1] == 1:
            return 0
        
        dp = [[0]*n for _ in range(m)]
        dp[0][0] = 1
        # dp[i][j] 从(0,0)出发到(i,j)的不同路径数
        for j in range(1, n):
            dp[0][j] = 1 if (dp[0][j-1] != 0 and obstacleGrid[0][j] != 1) else 0 
        for i in range(1, m):
            dp[i][0] = 1 if (dp[i-1][0] != 0 and obstacleGrid[i][0] != 1) else 0
        
        for i in range(1, m):
            for j in range(1, n):
                dp[i][j] = dp[i-1][j] + dp[i][j-1] if obstacleGrid[i][j] != 1 else 0
        
        return dp[-1][-1]

    
    def uniquePathsWithObstacles(self, obstacleGrid: List[List[int]]) -> int:
        m, n = len(obstacleGrid), len(obstacleGrid[0])
        if obstacleGrid[0][0] == 1 or obstacleGrid[-1][-1] == 1: return 0
        dp = [0]*n
        dp[0] = 1
        for j in range(1, n):
            dp[j] = 1 if dp[j-1] != 0 and obstacleGrid[0][j] != 1 else 0
        
        for i in range(1, m):
            dp[0] = 1 if dp[0] != 0 and obstacleGrid[i][0] != 1 else 0
            for j in range(1, n):
                dp[j] = dp[j-1] + dp[j] if obstacleGrid[i][j] != 1 else 0
        
        return dp[-1]

 

给定三个字符串 s1s2s3,请你帮忙验证 s3 是否是由 s1 和 s2 交错 组成的。

 

 

class Solution:
    def isInterleave(self, s1: str, s2: str, s3: str) -> bool:
        n1, n2, n3 = len(s1), len(s2), len(s3)

        # dp[i][j] 表示 s1[:i-1] 和 s2[:j-1] 是否能构成 s3[:i+j-2]
        if n1 + n2 != n3:
            return False

        
        dp = [[False]*(n2+1) for _ in range(n1+1)]
        dp[0][0] = True
        for j in range(1, n2+1):
            dp[0][j] = dp[0][j-1] and s2[j-1] == s3[j-1]
        for i in range(1, n1+1):
            dp[i][0] = dp[i-1][0] and s1[i-1] == s3[i-1]
        
        
        for i in range(1, n1+1):
            for j in range(1, n2+1):
                dp[i][j] = (dp[i-1][j] and s1[i-1] == s3[i+j-1]) or (dp[i][j-1] and s2[j-1] == s3[i+j-1])
            
        return dp[-1][-1]
        
class Solution {
public:
    bool isInterleave(string s1, string s2, string s3) {
        int n1 = s1.size(), n2 = s2.size(), n3 = s3.size();
        if((n1 + n2) != n3) return false;

        // dp[i][j]: s1[:i] 和 s2[:j] 是否能组成s3[:i+j]
        vector<vector<bool>> dp(n1+1, vector<bool>(n2+1, false));
        dp[0][0] = true;
        // s1 为空
        for(int j{1}; j<n2+1; j++){
            dp[0][j] = dp[0][j-1] && s2[j-1] == s3[j-1];
        }
        // s2 为空
        for(int i{1}; i<n1+1; i++){
            dp[i][0] = dp[i-1][0] && s1[i-1] == s3[i-1];
        }

        for(int i{1}; i<n1+1; i++){
            for(int j{1}; j<n2+1; j++){
                dp[i][j] = (dp[i-1][j] && s1[i-1] == s3[i+j-1]) || (dp[i][j-1] && s2[j-1] == s3[i+j-1]);
            }
        }

        return dp[n1][n2];
    }
};

 

 

119. 杨辉三角 II

你可以优化你的算法到 O(rowIndex) 空间复杂度吗?

class Solution {
public:
    vector<int> getRow(int rowIndex) {
        // 已经经过路径压缩了
        vector<int> res(rowIndex+1, 1);
        for(int i{1}; i<=rowIndex; i++){
            for(int j{i-1}; j>0; j--){       // 每行的第一个元素和最后一个元素都是1
                res[j] = res[j] + res[j-1];
            }
        }
        return  res;
    }
};

 

 

120. 三角形最小路径和

 

class Solution {
public:
    // 从上到下
    int minimumTotal1(vector<vector<int>>& triangle) {
        int n = triangle.size();

        // dp[i][j]:从(0,0)到(i,j)的最小路径和
        // 如果是i==j, dp[i][j] = dp[i-1][j-1] + t[i][j]
        // 如果i != j, dp[i][j] = min(dp[i-1][j-1], dp[i-1][j]) + t[i][j]
        vector<vector<int>> dp(n, vector<int>(n, 0));

        dp[0][0] = triangle[0][0];
        for(int i{1}; i<n; i++){
            dp[i][0] = dp[i-1][0] + triangle[i][0];
        }

        for(int i{1}; i<n; i++){
            for(int j{1}; j<i+1; j++){
                if(i == j){
                    dp[i][j] = dp[i-1][j-1] +  triangle[i][j];
                }else{
                    dp[i][j] = min(dp[i-1][j-1], dp[i-1][j]) + triangle[i][j];
                }
            }
        }
    
        return *min_element(dp[n-1].begin(), dp[n-1].end());
    }


    // 从下到上
    // dp[i][j] 表示从最后一行走到 (i,j)时的最小路径和
    // dp[0][0] 记为需要返回的值
    int minimumTotal2(vector<vector<int>>& triangle) {
        int n = triangle.size();
        vector<vector<int>> dp(n, vector<int>(n, 0));
        for(int j{0}; j < n; j++){
            dp[n-1][j] = triangle[n-1][j];
        }

        for(int i{n-2}; i>=0; i--){
            for(int j{0}; j <=i; j++){
                // 每个上一行元素,都必定有i+1,j 和 i+1,j+1
                dp[i][j] = min(dp[i+1][j+1], dp[i+1][j]) + triangle[i][j];
            }
        }

        return dp[0][0];
    }


    // 从下到上,路径压缩
    int minimumTotal(vector<vector<int>>& triangle) {
        int n = triangle.size();
        vector<int> dp{triangle.back()};

        for(int i{n-2}; i >= 0; i--){
            for(int j{0}; j<=i; j++){
                dp[j] = min(dp[j+1], dp[j]) + triangle[i][j];
            }
        }
        return dp[0];

    }

};

 

 
 
 
 

 

 

 

 

 

 

 

 

1.分割等和子集

 

 1 class Solution(object):
 2     def canPartition(self, nums):
 3         if(sum(nums)&1):
 4             return False
 5         
 6         target=sum(nums)//2
 7 
 8         # dp[i]表示是否能从 nums中取出一些数字,其和为i
 9         dp=[False]*(target+1)
10 
11         dp[0]=True
12 
13         for num in nums:
14             for i in range(target,num-1,-1):
15                 dp[i]=dp[i] or dp[i-num]
16         
17         return dp[target]

 

2.coins change i

组成amount的最少硬币数

 

 1 class Solution(object):
 2     def coinChange(self, coins, amount):
 3         # dp[i]表示凑成金额i所需的最少硬币数
 4         # dp[i]=min(dp[i],dp[i-coins[j]] if i-coins[j]>=0)
 5         # dp[0]=0 
 6 
 7         dp=[float('inf') for j in range(amount+1)]
 8         dp[0]=0
 9 
10         for j in range(1,amount+1):
11             for i in range(len(coins)):
12                 if(j>=coins[i] and dp[j-coins[i]]!=float('inf')):
13                     dp[j]=min(dp[j],dp[j-coins[i]]+1)
14             
15         return dp[amount] if dp[amount]!=float('inf') else -1
16             

 

 

3.1 coins change ii

组成amounts的所有可能数

 

 

 1 class Solution(object):
 2     def change(self, amount, coins):
 3         m=len(coins)
 4         n=amount
 5 
 6         dp=[[0]*(n+1)]*(m+1)
 7         dp[0][0]=1
 8 
 9         # 下面写法错误,没有任何硬币,所以无法组成
10         # for j in range(n+1):
11         #     if j %coins[0]==0:
12         #         dp[0][j]=1
13         
14         for i in range(1,m+1):
15             dp[i][0]=1
16 
17         for i in range(1,m+1):
18             for j in range(1,n+1):
19                 dp[i][j]=dp[i-1][j]+(dp[i][j-coins[i-1]] if j-coins[i-1]>=0 else 0)
20         
21         return dp[m][n]
def change(self, amount, coins):
        m=len(coins)
        n=amount

        # dp[i]表示组成i的组合数
        dp=[0]*(n+1)
        dp[0]=1

        for i in range(m):
            for j in range(coins[i],n+1):
                dp[j]=dp[j]+dp[j-coins[i]]
        
        return dp[amount]

 

3.2 coins change i

组成amount所需的最少硬币数

 

 1 class Solution(object):
 2     def coinChange(self, coins, amount):
 3         """
 4         :type coins: List[int]
 5         :type amount: int
 6         :rtype: int
 7         """
 8 
 9         m=len(coins)
10         n=amount
11 
12         # dp[j]表示组成amount j所需的最少硬币数
13         dp=[float('inf') for j in range(n+1)]
14 
15         dp[0]=0
16         for j in range(1,n+1):
17             for i in range(m):
18                 if(j>=coins[i]):
19                     dp[j]=min(dp[j],dp[j-coins[i]]+1)
20             
21         return dp[n] if dp[n]!=float('inf') else -1

 

 

 

4. 打家劫舍

 1 class Solution(object):
 2     def helper(self,nums):
 3         # dp[i]表示偷 前i个房子时 最高的金额数
 4         dp=[0]*len(nums)
 5         dp[0]=nums[0]
 6 
 7         for i in range(1,len(nums)):
 8             dp[i]=max(dp[i-1],nums[i]+(dp[i-2] if i-2>=0 else 0))
 9         
10         return dp[-1]
11 
12     def rob(self, nums):
13         if(len(nums)==0):
14             return 0
15 
16         if(len(nums)==1):
17             return nums[0]
18         
19         if(len(nums)==2):
20             return max(nums[0],nums[1])
21 
22         nums1=nums[:-1]
23         nums2=nums[1:]
24 
25         return max(self.helper(nums1),self.helper(nums2))

 

 

5.LIS

 

 1 class Solution(object):
 2     def lengthOfLIS(self, nums):
 3         n=len(nums)
 4         if(n==0 or n==1):
 5             return n
 6 
 7         dp=[1]*n
 8 
 9         for i in range(1,n):
10             for j in range(i):
11                 if(nums[j]<nums[i]):
12                     dp[i]=max(dp[j]+1,dp[i])
13         
14         return max(dp)

 

 

6.最大和连续子数组

 

 1 class Solution(object):
 2     def maxSubArray(self, nums):
 3         n=len(nums)
 4         if(n==0):
 5             return 0
 6 
 7         curSum=0          
 8         maxSum=float('-inf')
 9 
10         for i in range(n):
11             curSum+=nums[i]
12             maxSum=max(curSum,maxSum)
13 
14             if(curSum<0):
15                 curSum=0
16 
17 
18         return maxSum

 

 

7.众数

 

 1 class Solution(object):
 2     def majorityElement(self, nums):
 3         n=len(nums)
 4         if(n==0):
 5             return []
 6         
 7         if(n==1):
 8             return nums
 9 
10         res=[]
11 
12         num1=float('inf')
13         num2=float('inf')
14         cnt1=0
15         cnt2=0
16 
17         for i in range(n):
18             if(nums[i]==num1):
19                 cnt1+=1
20             elif(nums[i]==num2):
21                 cnt2+=1
22             elif(cnt1==0):
23                 num1=nums[i]
24                 cnt1=1
25             elif(cnt2==0):
26                 num2=nums[i]
27                 cnt2=1
28             else:
29                 cnt1-=1
30                 cnt2-=1
31   
32         cnt1,cnt2=0,0
33         for num in nums:
34             if(num==num1):
35                 cnt1+=1
36             elif(num==num2):
37                 cnt2+=1
38             
39         if(cnt1>n//3):
40             res.append(num1)
41         if(cnt2>n//3):
42             res.append(num2)
43 
44         return res

误区1:

num1和num2初始化为nums[0]。再执行循环。

假设数组中只有两个不相同的元素,那么结束循环时,num1和num2仍指向同一个元素

 

 

 

91解码方式

class Solution:
    def numDecodings(self, s: str) -> int:
        # dp[i]: s[:i] (不含i)可以解码的次数
        # dp[i] += dp[i-1] if s[i-1]是合法的
        # dp[i] += dp[i-2] if s[i-2:i]是合法的
        n = len(s)
        if n == 1:
            if s == "0":
                return 0
            return 1
        
        dp = [0]*(n+1)
        dp[0] = 1
        for i in range(1, n+1):
            if 0 < int(s[i-1]) < 10:
                dp[i] += dp[i-1]
            
            if i > 1 and 10 <= (int(s[i-2])*10 + int(s[i-1])) <= 26:
                dp[i] += dp[i-2]
        
        return dp[n]
        
def numDecodings(self, s: str) -> int:
        n = len(s)
        if n == 1:
            if s == "0":
                return 0
            return 1
        
        pprev, prev = 1, 1
        for i in range(1, n+1):
            cur = 0
            if 1 <= int(s[i-1]) < 10:
                cur += prev
            if i > 1 and 10 <= int(s[i-2:i]) <= 26:
                cur += pprev

            pprev, prev = prev, cur

        return cur

 

posted @ 2020-03-19 11:59  7aughing  阅读(142)  评论(0编辑  收藏  举报