Tags——Dynamic Programming

按tags刷leetcode,这里是动态规划部分。
推荐一个博客大佬动态规划部分的总结:
LeetCode中的两道动态规划题目 https://blog.csdn.net/baimafujinji/article/details/78920814
LeetCode中的动态规划题目解答(2) https://blog.csdn.net/baimafujinji/article/details/78928845
LeetCode中的动态规划题目解答(3) https://blog.csdn.net/baimafujinji/article/details/78930037

买卖股票最大利润问题

121:Best Time to Buy and Sell Stock
**题目要求:**输入一个数组,例如[7,1,5,3,6,4],第i个数字表示第i天个股票价格,之允许买卖一次,求最大利润。
**解题思路:**遍历数组,记录下最小的价格和利润值(当前价格-最小价格),不断更新利润值。

class Solution:
    def maxProfit(self, prices):
        """
        :type prices: List[int]
        :rtype: int
        """
        max_profit,low_price = 0,float('inf')
        for i in prices:
            low_price = min(low_price,i)
            max_profit = max(max_profit,i - low_price)
        return max_profit    

跨一步或两步台阶,代价最少

746: Min Cost Climbing Stairs
**题目要求:**给定一个数组cost = [1, 100, 1, 1, 1, 100, 1, 1, 100, 1],代表的是台阶,每一个数字代表该台阶的损失值,一次可以跨一步或者两步,希望损失值最小。注意, 可以从第一个台阶或第二个台阶起步。
**解题思路:**设定两个值res1,res2 = cost[0],cost[1],分别代表两种起步的损失值,遍历数组,找到迈向第i个台阶时的损失值(就是前i-2和前i-1阶损失值中更小的那个,加上第i阶的损失值),还要将res2赋值给res1(res1的值也要同步更新,这个很重要!)

class Solution:
    def minCostClimbingStairs(self, cost):
        """
        :type cost: List[int]
        :rtype: int
        """
        if len(cost)==0 or len(cost)==1:
            return 0
        res1,res2 = cost[0],cost[1]  
        for i in range(2,len(cost)):
            res1,res2 = res2,min(res1,res2)+cost[i]
        return min(res1,res2)

爬楼梯的所有爬法

leetcode 70. Climbing Stairs
题目描述:已知楼梯层数,一次可以爬一格或者两格,问一共有多少种爬法。
我第一反应是递归算法:

class Solution:
   def climbStairs(self, n):
       """
       :type n: int
       :rtype: int
       """
       if n==1:return 1
       if n==2:return 2
       return self.climbStairs(n-1)+self.climbStairs(n-2)

Run的时候可以通过,Submit的时候会报超时,无奈只能放弃递归这条路,借用上面那一题的思路来做。

class Solution:
    def climbStairs(self, n):
        """
        :type n: int
        :rtype: int
        """
        if n==1:return 1
        if n==2:return 2
        res1,res2=1,2  
        for i in range(3,n+1):
            res1,res2 = res2,res1+res2
        return res2

第二种解法的速度比第一种快多了!

抢劫犯

leetcode198. House Robber
题目要求:给定一个数组[2,7,9,3,1],每个数字代表每家的钱,小偷不能连续偷两家,计算偷到的最大钱数。

class Solution:
    def rob(self, nums):
        """
        :type nums: List[int]
        :rtype: int
        """
        if not nums:return 0
        if len(nums)==1:return nums[0]
        if len(nums)==2:return max(nums[0],nums[1])
        res1,res2 = nums[0],nums[1]
        for i in range(2,len(nums)):
            res1,res2 = max(res1,res2),res1+nums[i]
        return max(res1,res2)

【最重要的两句代码:】
res1=max(res1,res2):不能写成res1=res2,因为不一定是间隔一个偷一家,也可以间隔两家偷,(举例[2,1,1,2],如果写成res1=res2答案是3,错的)
res2=res1+nums[i]:nums[i]和res1之间已经隔了一个res2了,所以可以放心加
最后找res1和res2的最大值即可。

记录二进制位

leetcode338. Counting Bits
题目要求:给定非负整数num,求[0,num]范围内每个数的二进制表示中‘1’的个数。
这种题感觉要靠积累,两个关键点:
1.二进制数统计‘1’的个数bin(i).count('1')
2.if not num:这句话的含义:不仅包括num为空的情况,也包括了num=[0]的情况,需要特别注意!

class Solution:
   def countBits(self, num):
       """
       :type num: int
       :rtype: List[int]
       """
       if not num:return [0]
       res = [0]
       for i in range(1,num+1):
           res.append(bin(i).count('1'))
       return res

回文子串问题

leetcode5:Longest Palindromic Substring最长回文子串

【解法1:】
子函数find每次返回的是回文子串的长度,因此需要maxlen来记录最大的长度,知道了子串长度,也知道了中心位置(循环变量i就是中心位置),向左向右分别再走maxlen/2,就是起止位置。

class Solution:
    def longestPalindrome(self, s):
        """
        :type s: str
        :rtype: str
        """
        start = end = 0
        for i in range(len(s)): 
            len1 = self.find(s,i,i) #aba
            len2 = self.find(s,i,i+1) #abba
            maxlen = max(len1,len2)
            if maxlen>end-start+1:
                start = i-(maxlen-1)//2
                end = i+maxlen//2
        return s[start:end+1]
           
    def find(self,s,left,right):
        while(left>=0 and right<len(s) and s[left]==s[right]):
                left-=1
                right+=1
        return right-left-1   

【解法2:】
与解法1的区别是,子函数find直接返回当前的最大回文子串,所以就不用再计算起止位置了。

class Solution:
    def longestPalindrome(self, s):
        """
        :type s: str
        :rtype: str
        """
        res = ""
        for i in range(len(s)):
            tmp = self.find(s,i,i)
            if len(tmp)>len(res):
                res = tmp
            tmp = self.find(s,i,i+1)
            if len(tmp)>len(res):
                res = tmp
        return res
    
    def find(self,s,left,right):
        while(left>=0 and right<len(s) and s[left]==s[right]):
            left-=1;right+=1
        return s[left+1:right]

leetcode647. Palindromic Substrings

class Solution(object):
   def countSubstrings(self, s):
       """
       :type s: str
       :rtype: int
       """
       res = 0
       for i in range(len(s)):
           res += self.find(s, i, i)  # 奇数
           res += self.find(s, i, i + 1)  # 偶数

       return res

   def find(self, s, left, right):
       res = 0
       while (left >= 0 and right < len(s) and s[left] == s[right]):
           res += 1
           left -= 1
           right += 1
       return res

整数拆分,使乘积最大

leetcode343. Integer Break
题目要求:将n拆成多个数字之和(没说几个),使乘积最大。
这道题先要找规律,我们发现,将一个数字拆成2、3这样的组合,可以使乘积最大,而且3比2好。因此,这道题目就转换成了如下思路:n/3可以得到一共有多少个3,然后计算n%3,如果余数为1,就加到第一个3上变成4,如果余数为2,就在列表最后再添加一个2。最后计算列表所有元素的乘积。使用reduce函数。

from functools import reduce
class Solution:
    def integerBreak(self, n):
        """
        :type n: int
        :rtype: int
        """
        if n==2:return 1
        if n==3:return 2
        list_3 = [3] * int(n/3)  #记录3的个数
        last = n%3
        if last==1:
            list_3[0]+=1
        if last==2:
            list_3.append(2)
        return reduce(lambda a,b:a*b,list_3)

#找各位不相同的数字
leetcode357. Count Numbers with Unique Digits
题目要求:给定n(n表示几位数,n=2就是两位数,10-99的意思),找该范围内各个位上不相同的数字,
解法:一位数的满足要求的数字是10个(0到9),二位数的满足题意的是81个,[10 - 99]这90个数字中去掉[11,22,33,44,55,66,77,88,99]这9个数字,还剩81个。通项公式为f(k) = 9 * 9 * 8 * … (9 - k + 2),那么我们就可以根据n的大小,把[1, n]区间位数通过通项公式算出来累加起来即可,参见代码如下:参考

class Solution:
    def countNumbersWithUniqueDigits(self, n):
        """
        :type n: int
        :rtype: int
        """
        if not n:return 1
        res = [9] * n
        res[0] = 10
        for k in range(1, n):
            i=9
            while (i >= 10 - k):
                res[k] = res[k] * i
                i -= 1
        return sum(res)

猜你喜欢

转载自blog.csdn.net/aaon22357/article/details/85017358