Leetcode 动态规划最长公共子序列+ 198HouseRobbingI+II +746Min Cost Climbing Stairs

动态规划解解题思路总结:

一个很复杂的问题可以分解成形式类似,模式更小的问题。先尝试解决这个小问题,再扩大到大问题。要从小问题中看出动态规划状态转移式(表达式)。

最长公共子串LCSubstring

str1='abcdscde'
str2='jaserewcderew'

def getNumofCommonSubStr(str1,str2):
    lenstr1=len(str1)
    lenstr2=len(str2)
    record=[[0 for i in range(lenstr2+1)] for j in range(lenstr1+1)]# 多一位
    maxNum=0
    p=0

    for i in range(lenstr1):
        for j in range (lenstr2):
            if str1[i] == str2[j]:
                record[i+1][j+1]=record[i][j]+1
                if record[i+1][j+1]>maxNum:
                    maxNum=record[i+1][j+1]
                    p=i+1

    for row in record:
        print(row)
    return str1[p-maxNum:p],maxNum
longestsubstr,len_longestsubstr=getNumofCommonSubStr(str1,str2)
print(longestsubstr)
print(len_longestsubstr)

输出结果是cde,长度是3

 

LCSequence(最长公共子序列)

https://blog.csdn.net/hrn1216/article/details/51534607 这篇教程特别好,图文并茂,本题图摘自他

https://blog.csdn.net/littlethunder/article/details/25637173 也不错

关键是要明白LCS的递推公式:

如果看不懂公式,可以尝试理解下面的原理:

 

r

 

 

 

a="13456778"
b="357486782"
lena=len(a)
lenb=len(b)
c=[[0 for i in range(lenb+1)] for j in range(lena+1)]
flag=[[0 for i in range(lenb+1)] for j in range(lena+1)]
for i in range(lena):
    for j in range(lenb):
        if a[i]==b[j]:
            c[i+1][j+1]=c[i][j]+1
            flag[i+1][j+1]='ok'
        elif c[i+1][j]>c[i][j+1]:
            c[i+1][j+1]=c[i+1][j]
            flag[i+1][j+1]='left'
        else:
            c[i+1][j+1]=c[i][j+1]
            flag[i+1][j+1]='up'
#result=c[lena][lenb]#最长公共子序列的长度

def printLcs(flag,a,i,j):
    if i==0 or j==0:
        return
    if flag[i][j]=='ok':
        printLcs(flag,a,i-1,j-1)
        print(a[i-1],end='')
    elif flag[i][j]=='left':
        printLcs(flag,a,i,j-1)
    else:
        printLcs(flag, a, i - 1, j)


#输出LCS长度矩阵
for i in c:
   print(i)
print('')
#输出FLAG 矩阵
for j in flag:
   print(j)
print('')
#输出最长公共子串
printLcs(flag,a,len(a),len(b))
print('')


 

HouseRoubing

在Leetcode上刷的第一道动态规划的题就是当年卜老师的一道作业题,如下:

 

You are a professional robber planning to rob houses along a street. Each house has a certain amount of money stashed, the only constraint stopping you from robbing each of them is that adjacent houses have security system connected and it will automatically contact the police if two adjacent houses were broken into on the same night.

Given a list of non-negative integers representing the amount of money of each house, determine the maximum amount of money you can rob tonight without alerting the police.

Credits:
Special thanks to @ifanchu for adding this problem and creating all test cases. Also thanks to @ts for adding additional test cases.

我的解法:

 

class Solution(object):
    def rob(self, nums):
        """
        :type nums: List[int]
        :rtype: int
        """
        length=len(nums)
        if length==0:
             return 0
        elif length==1:
             return nums[0]
        elif length ==2:
             return max(nums[0],nums[1])
        else:
            OPT=length*[0]#OPT代表到第i个位置时抢劫所获的最大收益
            OPT[0]=nums[0]
            OPT[1]=max(nums[0],nums[1])
            for i in range(2,length):
                OPT[i]=max((OPT[i-2]+nums[i]),OPT[i-1])

            return OPT[-1]

 

 

 

 

 

思路:

最优子结构假设输入的数组长度为 n,为了求解到最后一个房子 n-1 的最大收益,我们先求解形式完全一样,但规模更小的子问题:从 i=2 开始求到第 i 个房子为止的最大收益,并把结果记录在 OPT[i]中,直到求到 i=n-1。这样,OPT[i]就能利用 OPT[i-2]或者 OPT[i-1]的值。(所以满足最优子结构性质:问题的最优解由相关子问题的最优解组合而成,而这些子问题可以独立求解。)

状态转移方程:OPT[i]=max(OPT[i-2]+value[i],OPT[i-1])

 

进阶HouseRobbingII:(话说进阶套路和作业都一样)

 

Note: This is an extension of House Robber.

After robbing those houses on that street, the thief has found himself a new place for his thievery so that he will not get too much attention. This time, all houses at this place are arranged in a circle. That means the first house is the neighbor of the last one. Meanwhile, the security system for these houses remain the same as for those in the previous street.

Given a list of non-negative integers representing the amount of money of each house, determine the maximum amount of money you can rob tonight without alerting the police.

Credits:
Special thanks to @Freezen for adding this problem and creating all test cases.

我的解法:(可能因为定义了子函数,确实不怎么快)

class Solution(object):
    def rob(self, nums):
        """
        :type nums: List[int]
        :rtype: int
        """
        def robway(nums):
                OPT=(length-1)*[0]#OPT代表到第i个位置时抢劫所获的最大收益 
                #length-1是指len(nums)-1,因为传进来的nums少了一个数 
                OPT[0]=nums[0]  
                OPT[1]=max(nums[0],nums[1])  
                for i in range(2,length-1):  
                    OPT[i]=max((OPT[i-2]+nums[i]),OPT[i-1])  


                return OPT[-1]  
            
        length=len(nums)  
        if length==0:  
                 return 0  
        elif length==1:  
                 return nums[0]  
        elif length==2 or length==3:#这里要注意,不是返回哪个特定位置的数,是返回最大值
                 return max(nums)
        else:
                 return max(robway(nums[:-1]),robway(nums[1:]))
            

 

我的思路:

如果这 n 个房子变成一个环时,输入为 value[0,1…,n-1]可视作 value[0]和 value[n-1]相邻,可分两种情况考虑:○1 选第 1 个房子(value[0])不选最后一个房子(value[n-1])○2 不选第 1 个房子(value[0])选最后一个房子(value[n-1])分别计算两种情况的最大收益,返回其中的最大值。

 



746Min Cost Climbing Stairs

On a staircase, the i-th step has some non-negative cost cost[i] assigned (0 indexed).

Once you pay the cost, you can either climb one or two steps. You need to find minimum cost to reach the top of the floor, and you can either start from the step with index 0, or the step with index 1.

Example 1:

Input: cost = [10, 15, 20]
Output: 15
Explanation: Cheapest is start on cost[1], pay that cost and go to the top.

 

Example 2:

Input: cost = [1, 100, 1, 1, 1, 100, 1, 1, 100, 1]
Output: 6
Explanation: Cheapest is start on cost[0], and only step on 1s, skipping cost[3].

 

Note:

  1. cost will have a length in the range [2, 1000].
  2. Every cost[i] will be an integer in the range [0, 999].

我自己的AC的方法(55ms):

 

class Solution(object):
    def minCostClimbingStairs(self, cost):
        """
        :type cost: List[int]
        :rtype: int
        """
        STEP=[0]*len(cost)
        STEP[0]=cost[0]
        STEP[1]=cost[1]
        for i in range(2,len(cost)):
            STEP[i]=cost[i]+min(STEP[i-2],STEP[i-1])
        
        return min(STEP[-1],STEP[-2])


思路:STEP维护第i个位置为止的最小分数,所以关键的动态规划表达式理解为:STEP[i]=当前位置花销+前两个或者前一个的较小花销值。因为当前位置可能是从前一个也可能是从前两个的那个台阶迈过来的。


        
        
70Climbing Stairs        

 

 

You are climbing a stair case. It takes n steps to reach to the top.

Each time you can either climb 1 or 2 steps. In how many distinct ways can you climb to the top?

Note: Given n will be a positive integer.

 

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

(这就是时间最短的解法,30MS,与最快的22MS解法一样)

class Solution(object):
    def climbStairs(self, n):
        """
        :type n: int
        :rtype: int
        """
        if n==1:
            return 1
        else:
            dp=[0]*n
            dp[0]=1
            dp[1]=2
            for i in range(2,n):
                dp[i]=dp[i-2]+dp[i-1]#动态规划表达式

            return dp[-1]

 

121Best Time to Buy and Sell Stock

 

 

Say you have an array for which the ith element is the price of a given stock on day i.

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

Example 1:

Input: [7, 1, 5, 3, 6, 4]
Output: 5

max. difference = 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

In this case, no transaction is done, i.e. max profit = 0.
class Solution(object):
    def maxProfit(self, prices):
        """
        :type prices: List[int]
        :rtype: int
        """
        max_profit, min_price = 0, float('inf')
        for price in prices:
            min_price = min(min_price, price)
            profit = price - min_price
            max_profit = max(max_profit, profit)
        return max_profit

不明白为什么这道题属于DP,其实不难,想明白思路就能写出来。

时间复杂度:O(n)

思路:遍历prices数组,对每一个price,维护min_price和max_profit

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值