LeetCode动态规划类题目汇总

 

目录

一、53.Maximum Subarray

题目

解答

二、70. Climbing Stairs

题目

解答

三、121. Best Time to Buy and Sell Stock

题目

解答

四、House Robber

题目

解答

五、Delete Operation for Two Strings

题目

解答


一、53.Maximum Subarray

题目

最大子数组,给定一个整数数组nums,找到其中和最大的连续的子数组,并返回它们相加的和。例子:

Input: [-2,1,-3,4,-1,2,1,-5,4],
Output: 6
Explanation: [4,-1,2,1] has the largest sum = 6.

解答

该题解答的思想主要为用两个变量,一个变量maxSoFar记录全局目前为止的最大和,另一个变量maxEndingHere记录该串目前为止最大和,若maxEndingHere超过了maxSoFar,则更新maxSoFar的值为maxEndingHere的值。具体可见下面的例子

cbmbbz的解法

public static int maxSubArray(int[] A) {
    int maxSoFar=A[0], maxEndingHere=A[0];//maxSoFar为到目前为止,出现过的连续子数组中和的最大值,maxEndingHere为当前串截止到当前数字之前和的最大值
    for (int i=1;i<A.length;++i){
    	maxEndingHere= Math.max(maxEndingHere+A[i],A[i]);//比较当前数字是加上该串之前的数字更大,还是不加更大,
//其实也就是判断该数字前的和是正数还是负数,如果是正数,就加上,是负数会拖累自己,就甩掉之前的从头开始
    	maxSoFar=Math.max(maxSoFar, maxEndingHere);//看看当前串的值有没有超过最大值,超过了则对最大值进行更新。
    }
    return maxSoFar;
}

实例:

以输入的串[-2,1,-3,4,-1,2,1,-5,4]为例,初始化maxSoFar=-2,maxEndingHere=-2.

接下来i=1

maxEndingHere=Math.max(-2+1,1);//maxEndingHere=1,此处由于前面的和为负,所以抛弃前面的,开始一个新串

maxSoFar=Math.max(-2,1);//maxSoFar更新为1,因为此时当前串以A[1]开头,长度为1,该串的和超过了之前的最大值-2,所以此处更新maxSoFar。

再接下来i=2

maxEndingHere=Math.max(1+(-3),-3);//maxEndingHere=-2,此处前面的和为正,所以延续前面的串

maxSoFar=Math.max(1,-2);//此处不更新maxSoFar,新产生的以A[1]开头,长度为2的串的和小于之前的最大值,所以不更新MaxSoFar的值。

。。。。以此类推

 

二、70Climbing Stairs

 

题目

你正在爬一个楼梯,楼梯有n个台阶,你每次只能走一个或两个台阶,那么你有多少种方式可以爬到顶呢?(n是正整数)例子:

Example 1:

Input: 2
Output: 2
Explanation: There are two ways to climb to the top.
1. 1 step + 1 step
2. 2 steps

Example 2:

Input: 3
Output: 3
Explanation: There are three ways to climb to the top.
1. 1 step + 1 step + 1 step
2. 1 step + 2 steps
3. 2 steps + 1 step

解答

这个题我在招商银行和京东的笔试中见过,印象非常深,所以很快写出了如下递归程序(其实就是斐波那契数列)。原因如下,设有n个台阶,那么只看最后一步怎么走,因为最后一步只有两种情况,走一个台阶或者两个,分开讨论:若最后一步只走一个台阶,那么可能的方式为前(n-1)个台阶所有可能的走的方式;若最后一步走两个台阶,那么可能的方式为(n-2)个台阶所有可能的走的方式.所以对于n个台阶来说,可能的走的方式为(n-1)和(n-2)的方式相加。

public int climbStairs(int n) {
    if(n<=2)
        return n;
    return(climbStairs(n-1)+climbStairs(n-2));

}

该方法时间超了,这也是递归的弊病,占用内存多,花费时间多,好处是代码简单明了,查了一下递归非递归转化,将算法转化为非递归,其实就是用循环来做

class Solution {
  public int climbStairs(int n) {
    if (n <= 2)
      return n;

    int pre1 = 2, pre2 = 1,temp=0;//pre1代表一步之前,也就是(n-1)的可能方式,pre2代表(n-2)的可能方式

    for (int i = 3; i < n; i++) {
      temp=pre2;
      pre2 = pre1;
      pre1 += temp;
    }

    return pre1 + pre2;
}
}

 

三、121Best Time to Buy and Sell Stock

题目

假设你有一个数组,其中第i个元素是第i天的指定股票的价格。如果你只能进行一次交易,设计算法来获得最大的收益。注意,只有买了才能卖。

If you were only permitted to complete at most one transaction (i.e., buy one and sell one share of the stock), design an algorithm to find the maximum profit.

Note that you cannot sell a stock before you buy one.

Example 1:

Input: [7,1,5,3,6,4]
Output: 5
Explanation: Buy on day 2 (price = 1) and sell on day 5 (price = 6), profit = 6-1 = 5.
             Not 7-1 = 6, as selling price needs to be larger than buying price.

Example 2:

Input: [7,6,4,3,1]
Output: 0
Explanation: In this case, no transaction is done, i.e. max profit = 0.

解答

这其实非常类似最大子数组的问题,看不出来?以第一个例子为例,我们求第i+1和第i天的股票差(我们可以赚多少)。[-6,4,-2,3,-2],第一个例子中最大收益是5,也就是该股票差数组的最大子数组的和。最高票答案如下,这个和最大子数组的唯一区别在于这个题我们可以选择不交易,也就是收益最少为0,不可能为负。

andyreadsall

public int maxProfit(int[] prices) {
        int maxCur = 0, maxSoFar = 0;
        for(int i = 1; i < prices.length; i++) {
            maxCur = Math.max(0, maxCur += prices[i] - prices[i-1]);//如果收益为负,那就取0.
            maxSoFar = Math.max(maxCur, maxSoFar);
        }
        return maxSoFar;
    }

 

四、House Robber

题目

你是一个专业的强盗,计划抢劫一条街上的房屋。每间房里存储了一定数量的金钱, 唯一需要注意的是相临的房间有安保系统相连,如果相邻的房间在同一天夜里被抢,则会自动联系警察(简而言之,不能同时抢劫两间相邻的房间)。 

给定列表里的非负整数表示每间房里的钱币数量,计算得出你今晚能抢到的最大数额,前提是不惊动警察。

 

Example 1:

Input: [1,2,3,1]
Output: 4
Explanation: Rob house 1 (money = 1) and then rob house 3 (money = 3).
             Total amount you can rob = 1 + 3 = 4.

Example 2:

Input: [2,7,9,3,1]
Output: 12
Explanation: Rob house 1 (money = 2), rob house 3 (money = 9) and rob house 5 (money = 1).
             Total amount you can rob = 2 + 9 + 1 = 12.

解答

对于每间房子,都有两种选择,a.偷当前房子,收益为前前所房子的收益加上今天房子的收益;b.不偷当前房子,那收益为上一所房子的最大收益。代码如下:这段代码写得简洁明了,忘记是从哪里看到的了,非常抱歉,如果有知情人,请告知。

 

    int prevNo = 0;//不偷上一家的收益

    int prevYes = 0;//偷了上一家的收益

    for (int n : num) {

//假设当前的n是偷第i家的收益

        int temp = prevNo;//不偷第i-1家的收益

//警告,接下来的prevNo和prevYes都是针对第i+1家计算的

        prevNo = Math.max(prevNo, prevYes);//假设此时是第i家,那么

//preNo和preYes分别表示不偷第i-1家和偷第i-1家的收益。问题是第i家就要过去啦,我们要为

//第i+1家开始计算啦,所以该行计算的是第i+1家的prevNo,也就是不偷第i家,因为是不偷第i家

//的收益,所以不加n。

        prevYes = n + temp;//对第i+1家来说,如果偷前一家,也就是第i家要偷,所以要加n,也就是第i家的收益要加上,temp是不偷第i-1家的收益,这样才能偷第i家。

    }

    return Math.max(prevNo, prevYes);

 

 

接下来的解法是LeetCode上的高票答案,其实和上述答案差不多,a和b分别相当于preYes和preNo。

#define max(a, b) ((a)>(b)?(a):(b))
int rob(int num[], int n) {
    int a = 0;
    int b = 0;
    
    for (int i=0; i<n; i++)
    {
        if (i%2==0)
        {
            a = max(a+num[i], b);
        }
        else
        {
            b = max(a, b+num[i]);
        }
    }
    
    return max(a, b);
}

五、Delete Operation for Two Strings

题目

Given two words word1 and word2, find the minimum number of steps required to make word1 and word2 the same, where in each step you can delete one character in either string.

Example 1:

Input: "sea", "eat"
Output: 2
Explanation: You need one step to make "sea" to "ea" and another step to make "eat" to "ea".

Note:

  1. The length of given words won't exceed 500.
  2. Characters in given words can only be lower-case letters.

解答

To make them identical, just find the longest common subsequence. The rest of the characters have to be deleted from the both the strings, which does not belong to longest common subsequence.

public int minDistance(String word1, String word2) {
    int dp[][] = new int[word1.length()+1][word2.length()+1];
    for(int i = 0; i <= word1.length(); i++) {
        for(int j = 0; j <= word2.length(); j++) {
            if(i == 0 || j == 0) dp[i][j] = 0;
            else dp[i][j] = (word1.charAt(i-1) == word2.charAt(j-1)) ? dp[i-1][j-1] + 1
                    : Math.max(dp[i-1][j], dp[i][j-1]);
        }
    }
    int val =  dp[word1.length()][word2.length()];
    return word1.length() - val + word2.length() - val;
}

 

 

 

 

 

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值