本周算法题总结(关于动态规划的一些基本题)

这周做了一些关于动态规划的基础题,先总结一些自己的学习心得

青蛙跳台阶

一只青蛙一次可以跳上1级台阶,也可以跳上2级台阶。求该青蛙跳上一个 n 级的台阶总共有多少种跳法。

答案需要取模 1e9+7(1000000007),如计算初始结果为:1000000008,请返回 1。

分析:

设青蛙跳上n级台阶共有f(n)种跳法

不难看出,当n>2时,第一次跳台阶时会有两种选择:第一种是第一次跳一级,则第一种的跳法即为剩下的台阶数的跳法f(n-1);第二种是第一次跳两级,则第二种跳法为剩下的n-2级台阶的跳法即f(n-2)。总的f(n)就为两种选择相加。

n=1时,f(1)=1

n=2时,f(2)=f(1)+1

n=3时,f(3)=f(2)+f(1)

n=4时,f(4)=f(3)+f(2)

int numWays(int n) {
            int i=1,j=1,result,t=n;
            if(n==1||n==0) return 1;
            while(t!=1)
            {
                result=(i+j)%1000000007;
                i=j;
                j=result;
                t--;
            }
            return result;
}

股票的最大利润

假设把某股票的价格按照时间先后顺序存储在数组中,请问买卖该股票一次可能获得的最大利润是多少?

输入: [7,1,5,3,6,4]
输出: 5
解释: 在第 2 天(股票价格 = 1)的时候买入,在第 5 天(股票价格 = 6)的时候卖出,最大利润 = 6-1 = 5 。
     注意利润不能是 7-1 = 6, 因为卖出价格需要大于买入价格。

分析:

设最大利润为max,设目前为止的最小股票价格为min,设当天的利润为pr[i],

pr[i]=price[i]-min

max=max(pr[i],pr[i-1])

int maxProfit(vector<int>& prices) {
        int min,i,profit=0,t;
        if(prices.size()<=1) return 0;
        min=prices[0];
        for(i=0;i<prices.size();i++)
        {
            if(min>prices[i])
            {
                min=prices[i];
                t=i;
            }
            if(prices[i]-min>profit)
            profit=prices[i]-min;
        }
        return profit;
    }

连续子数组的最大和

输入一个整型数组,数组中的一个或连续多个整数组成一个子数组。求所有子数组的和的最大值。

要求时间复杂度为O(n)。

输入: nums = [-2,1,-3,4,-1,2,1,-5,4]
输出: 6
解释: 连续子数组 [4,-1,2,1] 的和最大,为 6

分析:

要首先清楚的是,子数组的第一个数一定为正数,设add[i]为子数组开始相加一直到当前数的总和,max=max(add[i],add[i-1])

子数组的开始设为原题中的开始,然后相加,若相加后的add为为负数,那么前面的数就可以抛弃了,从当前开始重新相加,最后判断max,add中的较大一方并赋给max即可

int maxSubArray(vector<int>& nums) {
       int add=nums[0],max=nums[0],i;
       for(i=1;i<nums.size();i++)
       {
            if(add+nums[i]<nums[i])//表示前面的数的和为负数,放弃这个和,从这个数开始重新相加
            add=nums[i];
            else
            add+=nums[i];
            if(max<add)
            max=add;
       }
       return max;
    }

礼物的最大价值

在一个 m*n 的棋盘的每一格都放有一个礼物,每个礼物都有一定的价值(价值大于 0)。你可以从棋盘的左上角开始拿格子里的礼物,并每次向右或者向下移动一格、直到到达棋盘的右下角。给定一个棋盘及其上面的礼物的价值,请计算你最多能拿到多少价值的礼物?

输入: 
[
  [1,3,1],
  [1,5,1],
  [4,2,1]
]
输出: 12
解释: 路径 13521 可以拿到最多价值的礼物

分析:

用一个二维数组add[i][j]来表示到达(i,j)时能拿到的礼物的最大值累计量
只有一个元素时,最大值为自己
有一排元素时,最大值为自己的加上自己左边的
有一列时,最大值为自己的加上自己上面的
为多排多列时,最大值为自己的加上上面或左边中的较大一个

int maxValue(vector<vector<int>>& grid) {
        int i=0,j=0;
        int add[grid.size()][grid[0].size()];
        memset(add,0,sizeof(add));//测试用例中含有0,需初始化
        for(i=0;i<grid.size();i++)
        {
            for(j=0;j<grid[0].size();j++)
            {
                if(i==0&&j==0)
                add[i][j]=grid[i][j];
                if(i==0&&j>0)
                add[i][j]=add[i][j-1]+grid[i][j];
                if(j==0&&i>0)
                add[i][j]=add[i-1][j]+grid[i][j];
                if(i>0&&j>0)
                {
                    if(add[i-1][j]>=add[i][j-1])
                    add[i][j]=add[i-1][j]+grid[i][j];
                    if(add[i-1][j]<add[i][j-1])
                    add[i][j]=add[i][j-1]+grid[i][j];
                }
            }
        }
        return add[grid.size()-1][grid[0].size()-1];
    }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值