算法学习-动态规划-实战一

1 二维数组路径最小和(leetcode 64):

1.1 问题描述:

一个mn列的二维数组,每个元素是一个非负数,从左上角走到右下角,每次只能朝右或者下走,不能走出矩阵,使得总和最小。

1.2 算法思想:

1.3 代码:

class Solution {
public:
    int minPathSum(vector<vector<int> > &grid) {
        int M = grid.size();
        int N = grid[0].size();
        vector<int> paycost(N);
        for(int i=0; i<M; i++){
            for(int j=0; j<N; j++){
                if(i == 0){
                    if(j == 0){
                        paycost[j] = grid[i][j];
                    }else{
                        paycost[j] = paycost[j-1] + grid[i][j];
                    }
                }else if(j == 0){
                    paycost[j] = paycost[j] + grid[i][j];
                }else{
                    paycost[j] = min(paycost[j],paycost[j-1]) + grid[i][j];
                }
            }
        }
     return paycost[N-1];
    }
};


2  最大子数组求和(leetcode53):

2.1 问题描述:

一个整数数组,一个非空的子数组(连续一段数),使得它的和最大 (Leetcode 53)

2.1 算法思想:

1.2 代码:

a.分治(我的代码超时了,不知道为什么):

int divideAndCOnquermaxSubArray(vector<int>& nums,int start,int end){
        if(end < start)
            return 0;
        if(end == start)
            return 1;
        int t = (end - start + 1)>>1;
        int mid = start+((end - start + 1)>>1);
       
        int sum = max(divideAndCOnquermaxSubArray(nums,start,mid-1),
                      divideAndCOnquermaxSubArray(nums,mid+1,end));
        int leftSum = 0;
        int leftMax = 0;
        for(int i=mid; i>=0; i--){
            leftSum += nums[i];
            leftMax = leftMax>leftSum ? leftMax : leftSum;
        }
        int rightSum = 0;
        int rightMax = 0;
        for(int i=mid; i<=end; i++){
            rightSum += nums[i];
            rightMax = rightMax>rightSum ? rightMax : rightSum;
        }
        return max(sum,leftMax+rightMax-nums[mid]);
}

这个是我看的视频公开课的代码:

 b.动态规划:

int DynamicProgramingMaxSubArray(vector<int>& nums){
  int size = nums.size();
  vector<int> p(size);
  for(int i=0; i<size; i++){
   if(i == 0){
    p[i] = nums[i];
   }else{
    p[i] = max(nums[i], nums[i]+p[i-1]);
   }
  }
  int max;
  for(int i=0; i<size; i++){
      if(i==0)
          max = p[0];
      else if(max < p[i]){
          max = p[i];
      }
  }
  return max;
 } 
  //动态规划 优化空间 
 int DynamicProgramingMaxSubArrayGood(vector<int>& nums){
  int size = nums.size();
  int endHere;
  int maxAnd;
  for(int i=0; i<size; i++){
   if(i == 0){
    endHere = nums[i];
    maxAnd = endHere;
   }else{
    endHere = max(nums[i],endHere+nums[i]);
    maxAnd = max(maxAnd,endHere);
   }
  }
  return maxAnd;
 } 
c.线性枚举;
class Solution {
public:
    int maxSubArray(vector<int>& nums) {
        int size = nums.size();
	    int minSum,sum;
		int maxAnd;
		for(int i=0; i<size; i++){
			if(i == 0){
				sum = maxAnd = nums[i];
				minSum = min(0,nums[i]);
			}else{
			    sum += nums[i];
			    maxAnd = max(maxAnd,sum - minSum);
			    minSum = min(minSum,sum);
			}
		}
		return maxAnd;
    }
};

1.3 需要注意的问题:

a.在分治中,必须考虑还中点,和边界,由于我的中点开始时没有加start,一直没看出来,浪费了很多时间。

b.在线性枚举的时候也是对边界(i==0时),对minSum的处理考虑不足。

3.编辑距离(leetcode 72):

3.1 问题描述:

给定两个字符串ST,求把S变成T所需要的最少操作次数。操作包括:在任意位置增加一个字符、减少任意一个字符以及修改任意一个字符。 (Leetcode 72)

3.2 算法思想:

3.3 代码:

int minDistance(string word1, string word2) {
        int WL1 = word1.length();
        int WL2 = word2.length();
        vector<vector<int> > paycost(WL1+1,vector<int>(WL2+1));
        for(int i=0; i<=WL1; i++){
            for(int j=0; j<=WL2; j++){
                if(i == 0)
                    paycost[i][j] = j;
                else if(j == 0)
                    paycost[i][j] = i;
                else{
                    int cost0 = paycost[i-1][j-1] + (word1[i-1]==word2[j-1] ? 0 : 1);
                    int cost1 = paycost[i-1][j] + 1;
                    int cost2 = paycost[i][j-1] + 1;
                    paycost[i][j] = min(cost0,min(cost1,cost2));
                }
               // cout<<  paycost[i][j] <<"    ";
            }
          //  cout<<endl;
        }
        return paycost[WL1][WL2];
    }

空间优化:

class Solution {
public:
    int minDistance(string word1, string word2) {
        int WL1 = word1.length();
        int WL2 = word2.length();
        vector<int> paycost(WL2+1);
        int payPrePre = 0;
        for(int i=0; i<=WL1; i++){
            for(int j=0; j<=WL2; j++){
                if(i == 0)
                    paycost[j] = j;
                else if(j == 0){
                    payPrePre = paycost[j];
                    paycost[j] = i;
                }
                else{
                    int cost0 = payPrePre + (word1[i-1]==word2[j-1] ? 0 : 1);
                    int cost1 = paycost[j] + 1;
                    int cost2 = paycost[j-1] + 1;
                    payPrePre = paycost[j];
                    paycost[j] = min(cost0,min(cost1,cost2));
                }
            }
        }
        return paycost[WL2];
    }
};

3.4 需要注意的问题:

a.这个问题中,对问题的转换的的思想很重要,不容易想到。在coding中,对于下图情况A一般容易想到。对于B和C,由于在第一个时就要考虑前一个的情况,所以对于存储数组的大小要加一,以处理这一特殊情况。否则就要考虑很多边界情况。

b.对于空间优化:在处理(i,j)点时需要考虑三个点(i-1,j-1)、(i-1,j)、(i,j-1)。此时(i,j)点还未更新。故(i-1,j)、(i,j-1)可以用以为数组(j-1)、(j)两个点表示。对于(i-1,j-1)。考虑N点,对于N点的左上正好是在处理(i,j)点时更新前的(j),所以用一个变量存起来即可。但是在边界点F时要单独处理。否则处理F后一点就会出错。

4 总结:

本文主要参考视频公开课视频公开课上实战进行练习。对于动态规划,最重要的就是

a、递推式

b、初值

c、空间优化

在coding的过程中,一般容易出问题的就是初值和边界条件,写代码前最好现在纸上写,出了问题不要马上随便改一个地方继续试。这样会出行case by case的循环中。最好分析清楚再写,这样反而可以节约时间。

后续练习:

Leetcode (leetcode.com)题号 85, 91, 97, 120,131, 132, 139, 140, 152

5 参考资料:

http://www.julyedu.com/video/play/id/19




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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值