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];
}

64. Minimum Path Sum

int minPathSum(vector<vector<int>>& grid) {
    int m=grid.size();
    int n=grid[0].size();
    for (int i=1;i<n;i++){
        grid[0][i]=grid[0][i-1]+grid[0][i];
    }
    for (int i=1;i<m;i++){
        grid[i][0]=grid[i-1][0]+grid[i][0];
    }
    for(int i=1;i<m;i++){
        for (int j=1;j<n;j++){
            grid[i][j]=min(grid[i-1][j],grid[i][j-1])+grid[i][j];
        }
    }
    return grid[m-1][n-1];
}

70. Climbing Stairs

使用普通递归超时,换用备忘录

int climbStairs(int n) {
    if(n==1 || n==2 )
        return n;
    int *a=new int[n+1];
    a[1]=1;
    a[2]=2;
    for (int i=3;i<n+1;i++){
        a[i]=a[i-1]+a[i-2];
    }
    return a[n];
}

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背包逆序,完全背包顺序)

474. Ones and Zeroes

网址:https://leetcode.com/problems/ones-and-zeroes/
令dp[i][j]为i个0和j个1的时候的最大个数,状态转移方程:
dp[i][j] = max(dp[i][j], dp[i-zeros][j-ones] + 1)

int findMaxForm(vector<string>& strs, int m, int n) {
    vector<vector<int>>dp(m+1,vector<int>(n+1,0));
    int i,j;
    int ones,zeros;
    for (int k=0;k<strs.size();k++){
        ones=0;
        zeros=0;
        for (char c:strs[k]){
            if(c=='0')
                zeros++;
            if(c=='1')
                ones++;
        }
        for (i=m;i>=zeros;i--){
            for (j=n;j>=ones;j--){
                dp[i][j] = max(dp[i][j], dp[i-zeros][j-ones] + 1);

            }
        }
    }
    cout<<dp[m][n];

}
逆序的原因:正常情况下使用三维数组,即dp[k][i][j] = max(dp[k][i][j], dp[k-1][i-zeros][j-ones] + 1),由于只与dp[k-1][…][…]有关,简化为二维数组,因此逆序是为了使 dp[i-zeros][j-ones]仍然为k-1时的值。

494. Target Sum

网址:https://leetcode.com/problems/target-sum/
首先想到的是dp[i][j]=dp[i-1][j-nums[i]]+dp[i-1][j+nums[i]],即上一个数加减当前数得到想要的值,但是实际操作发现非常多异常情况需要考虑。
方法一
本题预先处理了数据,通过数学推理转换为01背包问题
思路:https://blog.csdn.net/qq_26410101/article/details/80855135 (思路二)

int findTargetSumWays(vector<int>& nums, int S) {
    if(nums.size()==0)
        return 0;
    int sum=accumulate(nums.begin(),nums.end(),0);
    if(S>sum || S<-sum || (sum+S)%2==1)
        return 0;
    sum=(sum+S)/2;
    vector<int>dp(sum+1,0);
    dp[0]=1;
    for(int i=0;i<nums.size();i++){
        for(int j=sum;j>=nums[i];j--){
            dp[j]=dp[j]+dp[j-nums[i]];
        }
    }
    return dp[sum];
}

方法二
使用开始想到的方程,采用备忘录法。

    int findTargetSumWays(vector<int>& nums, int S) {
        vector<unordered_map<int, int>> dp(n + 1);
        dp[0][0] = 1;
        for (int i = 0; i < nums.size(); ++i) {
            for (auto &a : dp[i]) {
                int sum = a.first, cnt = a.second;
                dp[i + 1][sum + nums[i]] += cnt;
                dp[i + 1][sum - nums[i]] += cnt;
            }
        }
        return dp[n][S];
    }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值