文章目录
按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)