1. 程式人生 > >leetcode 動態規劃題

leetcode 動態規劃題

5 Longest Palindromic Substring

網址:https://leetcode.com/problems/longest-palindromic-substring/submissions/
思路一:暴力破解
O(n^3)

思路二:動態規劃
時間複雜度:O(n^2), 空間複雜度:O( n ^ 2)
動態轉移方程:
if i == j,dp[i, j] = 1
if i = j + 1,dp[i, j] = s[i] == s[j]
if i > j + 1,dp[i, j] = s[i] == s[j] && dp[i + 1][j - 1]

string longestPalindrome(string s) {
    if(s.size()==0)               //考慮字串為0的情況
        return s;
    int max=0,start=0;
    bool dp[1001][1001]={false};
    for (int i=0;i<s.size();i++) {
        dp[i][i] = true;
    }
    for (int i=1;i<s.size();i++){
        for (int j=0;j<i;j++){
            if
(i==j+1 && s[i]==s[j]) dp[j][i]= true; if(s[i]==s[j] && dp[j+1][i-1] && i>j+1) dp[j][i]= true; if(dp[j][i] && i-j+1>max){ max=i-j+1; start=j; } } } if
(max==0) //考慮沒有找到大於等於2的迴文串 return s.substr(0,1); return s.substr(start,max); }

53 maximum subarray

網址:https://leetcode.com/problems/maximum-subarray/
狀態轉移方程:f=max(f+A[i],A[i])

int maxSubArray(vector<int>& nums) {
    vector<int> sum(nums.size(),0);
    sum[0]=nums[0];            
    int max=nums[0];
    for (int i=1;i<nums.size();i++){
        sum[i]=nums[i]+(sum[i-1]>0?sum[i-1]:0);
        max=(max<sum[i]?sum[i]:max);
    }
    cout<<max;
}

62 Unique Paths

思路:動態規劃
狀態轉移方程:dp[i][j]=dp[i-1][j]+dp[i][j-1]

1.使用普通遞迴:超時……

int getSteps(int m,int n){

    if(m==0 || n==0)
        return 1;
    return getSteps(m,n-1)+getSteps(m-1,n);

}

int uniquePaths(int m, int n) {
    int s=getSteps(m-1,n-1);
    cout<<s;
}

2.換用自底向上方法:擊敗100%……

int s[101][101];
int uniquePaths(int m, int n) {
    for (int i=0;i<m;i++){
        for (int j=0;j<n;j++){
            if(i==0 || j==0) {
                s[i][j] = 1;
            }
            else s[i][j]=s[i-1][j]+s[i][j-1];
        }
    }
    return s[m-1][n-1];
}

322. Coin Change

網址:https://leetcode.com/problems/coin-change/
狀態轉移方程:dp[i]=min(dp[i],dp[i-coins[j]]+1);

int  INF=0x7ffffffe;
int min(int a,int b){
    if(a<=b)
        return a;
    else return b;
}
int coinChange(vector<int>& coins, int amount) {
    if(amount==0)
        return 0;
    if(coins.size()==0)
        return 0;

    vector<int> dp(amount+1,INF);
    dp[0]=0;
    for (int i=1;i<=amount;i++){
        for (int j=0;j<coins.size();j++){
            if(coins[j]<=i)     //開始的時候忘了比較,使資料越界
                dp[i]=min(dp[i],dp[i-coins[j]]+1);
        }
    }
    if(dp[amount]==INF)
        return -1;
    else return dp[amount];

}

時間複雜度:O(amount*coins.size)
空間複雜度:O(amount)

416. Partition Equal Subset Sum

網址:https://leetcode.com/problems/partition-equal-subset-sum/
思路:
1)求出所有數字的和,若為奇數則一定不能分成兩個相等的組;
2)若為偶數,求出和的1/2數target,看能否在陣列中找到和為target的數。即轉換為恰能裝滿的01揹包問題
狀態轉移方程:dp[i] = dp[i] || dp[i - num],dp[i]的型別為布林型,代表陣列中是否存在數字使和為i。

bool canPartition(vector<int>& nums) {
    int sum = accumulate(nums.begin(), nums.end(), 0), target = sum >> 1;
    cout<<"target:"<<target<<endl;
    if (sum & 1) return false;
    vector<bool> dp(target + 1, false);
    dp[0] = true;
    for (int num : nums) {
        for (int i = target; i >= num; --i) {
            dp[i] = dp[i] || dp[i - num];
        }
    }
    return dp[target];
}
注意:
在動態規劃問題中要注意迴圈的順序,例如揹包問題:
1)揹包容量在內層迴圈;
2)內層迴圈採用順序還是逆序(01揹包逆序,完全揹包順序)