动态规划
给定一个整数数组 nums
,找到一个具有最大和的连续子数组(子数组最少包含一个元素),返回其最大和。
示例:
输入: [-2,1,-3,4,-1,2,1,-5,4], 输出: 6 解释: 连续子数组 [4,-1,2,1] 的和最大,为 6。
进阶:
如果你已经实现复杂度为 O(n) 的解法,尝试使用更为精妙的分治法求解。
1 class Solution: 2 def maxSubArray(self, nums: List[int]) -> int: 3 nums_len = len(nums) 4 if nums_len == 1: 5 return nums[0] 6 #dp[i]代表着以nums[i]为结尾的最大和的连续子数组 7 #dp[i] = max(dp[i-1]+nums[i], nums[i]) 8 dp = deepcopy(nums) 9 for i in range(1, nums_len): 10 dp[i] = max(dp[i-1]+nums[i], nums[i]) 11 12 return max(dp)
70. 爬楼梯
假设你正在爬楼梯。需要 n 阶你才能到达楼顶。
每次你可以爬 1 或 2 个台阶。你有多少种不同的方法可以爬到楼顶呢?
注意:给定 n 是一个正整数。
示例 1:
输入: 2 输出: 2 解释: 有两种方法可以爬到楼顶。 1. 1 阶 + 1 阶 2. 2 阶
示例 2:
输入: 3 输出: 3 解释: 有三种方法可以爬到楼顶。 1. 1 阶 + 1 阶 + 1 阶 2. 1 阶 + 2 阶 3. 2 阶 + 1 阶
1 class Solution: 2 def climbStairs(self, n: int) -> int: 3 #dp[i]代表当有i阶楼梯时有多少种方法可以到达楼顶 4 #dp[i] = dp[i-1] + dp[i-2] 5 dp = [1 for _ in range(n+1)] 6 7 for i in range(2, n+1): 8 dp[i] = dp[i-1] + dp[i-2] 9 10 return dp[-1]
121. 买卖股票的最佳时机
给定一个数组,它的第 i 个元素是一支给定股票第 i 天的价格。
如果你最多只允许完成一笔交易(即买入和卖出一支股票),设计一个算法来计算你所能获取的最大利润。
注意你不能在买入股票前卖出股票。
示例 1:
输入: [7,1,5,3,6,4] 输出: 5 解释: 在第 2 天(股票价格 = 1)的时候买入,在第 5 天(股票价格 = 6)的时候卖出,最大利润 = 6-1 = 5 。 注意利润不能是 7-1 = 6, 因为卖出价格需要大于买入价格。
示例 2:
输入: [7,6,4,3,1] 输出: 0 解释: 在这种情况下, 没有交易完成, 所以最大利润为 0。
1 class Solution: 2 def maxProfit(self, prices: List[int]) -> int: 3 if not prices: 4 return 0 5 prices_len = len(prices) 6 dp = [0 for _ in range(prices_len)] 7 8 for i in range(1, prices_len): 9 min_prices = min(prices[0:i]) 10 if min_prices < prices[i]: 11 dp[i] = prices[i] - min_prices 12 13 return max(dp)
5. 最长回文子串
给定一个字符串 A,找到 A中最长的回文子串。你可以假设 A
的最大长度为 1000。
示例 1:
输入: "babad" 输出: "bab" 注意: "aba" 也是一个有效答案。
示例 2:
输入: "cbbd" 输出: "bb"
解答:
#dp[i][j], 代表A[i:j+1]是否为回文串
#dp[i][j] = dp[i+1][j-1] and A[i] == A[j]
1 # -*- coding:utf-8 -*- 2 3 class Solution: 4 def getLongestPalindrome(self, A, n): 5 # write code here 6 if not A: 7 return 0 8 dp = [[False]*n for _ in range(n)] 9 # print(dp) 10 for i_index in range(n): 11 dp[i_index][i_index] = True 12 if i_index+1 < n and A[i_index] == A[i_index+1]: 13 dp[i_index][i_index+1] = True 14 15 for i_index in range(n-3, -1, -1): 16 for j_index in range(i_index+2, n): 17 if dp[i_index+1][j_index-1] and A[i_index] == A[j_index]: 18 dp[i_index][j_index] = True 19 res = 1 20 for i_index in range(n): 21 for j_index in range(i_index, n): 22 if dp[i_index][j_index]: 23 res = max(res, j_index-i_index+1) 24 print(res) 25 26 return res
516. 最长回文子序列
给定一个字符串s
,找到其中最长的回文子序列。可以假设s
的最大长度为1000
。
示例 1:
输入:
"bbbab"
输出:
4
一个可能的最长回文子序列为 "bbbb"。
示例 2:
输入:
"cbbd"
输出:
2
一个可能的最长回文子序列为 "bb"。
1 class Solution: 2 def longestPalindromeSubseq(self, s: str) -> int: 3 if not s: 4 return 0 5 n = len(s) 6 dp = [[0] * n for _ in range(n)] 7 for i in range(n): 8 dp[i][i] = 1 9 10 #dp[i][j] = dp[i+1][j-1] + 2 if s[i] == s[j] 11 #dp[i][j] = max(dp[i+1][j], dp[i][j-1]) if s[i] != s[j] 12 for i in range(n-1, -1, -1): 13 for j in range(i+1, n): 14 if s[i] == s[j]: 15 dp[i][j] = dp[i+1][j-1] + 2 16 else: 17 dp[i][j] = max(dp[i+1][j], dp[i][j-1]) 18 19 return dp[0][n-1]
221. 最大正方形
在一个由 0 和 1 组成的二维矩阵内,找到只包含 1 的最大正方形,并返回其面积。
示例:
输入: 1 0 1 0 0 1 0 1 1 1 1 1 1 1 1 1 0 0 1 0 输出: 4
设定状态: dp[i][j] 表示以(i, j)为右下顶点的最大全1矩阵的边长.
状态转移方程:
if matrix[i][j] == 0
dp[i][j] = 0
else // 此时为dp[i-1][j-1], dp[i-1][j], dp[i][j-1] 确定的区域的最大全1矩阵
dp[i][j] = min{dp[i-1][j-1], dp[i-1][j], dp[i][j-1]} + 1 // 得到此方程需要一定推导, 纸笔画一下
边界: if i == 0 or j == 0: dp[i][j] = matrix[i][j]
1 class Solution: 2 def maximalSquare(self, matrix: List[List[str]]) -> int: 3 if matrix == []: 4 return 0 5 # write your code here 6 row, col = len(matrix), len(matrix[0]) 7 dp = [[0]*col for i in range(row)] 8 9 for i in range(0, row): 10 if matrix[i][0] == "1": 11 dp[i][0] = 1 12 13 for j in range(0, col): 14 if matrix[0][j] == "1": 15 dp[0][j] = 1 16 17 for i in range(1, row): 18 for j in range(1, col): 19 if matrix[i][j] == "1": 20 dp[i][j] = min(dp[i-1][j-1], dp[i-1][j], dp[i][j-1])+1 21 else: 22 dp[i][j] = 0 23 24 max_edge = max(max(dp[i]) for i in range(row)) 25 26 return max_edge*max_edge
300. 最长上升子序列
给定一个无序的整数数组,找到其中最长上升子序列的长度。
示例:
输入:[10,9,2,5,3,7,101,18]
输出: 4 解释: 最长的上升子序列是[2,3,7,101],
它的长度是4
。
说明:
- 可能会有多种最长上升子序列的组合,你只需要输出对应的长度即可。
- 你算法的时间复杂度应该为 O(n2) 。
进阶: 你能将算法的时间复杂度降低到 O(n log n) 吗?
1 class Solution: 2 def lengthOfLIS(self, nums: List[int]) -> int: 3 nums_len = len(nums) 4 if nums_len <= 1: 5 return nums_len 6 #dp[i]代表着以nums[i]为结尾的最长上升子序列的长度 7 dp = [1 for _ in range(nums_len)] 8 9 for i in range(1, nums_len): 10 for j in range(i): 11 if nums[i] > nums[j] and dp[j]+1 > dp[i]: 12 dp[i] = dp[j] + 1 13 return max(dp)
377. 组合总和 Ⅳ
给定一个由正整数组成且不存在重复数字的数组,找出和为给定目标正整数的组合的个数。
示例:
nums = [1, 2, 3] target = 4 所有可能的组合为: (1, 1, 1, 1) (1, 1, 2) (1, 2, 1) (1, 3) (2, 1, 1) (2, 2) (3, 1) 请注意,顺序不同的序列被视作不同的组合。 因此输出为 7。
1 #动态规划 2 class Solution: 3 def combinationSum4(self, nums: List[int], target: int) -> int: 4 nums_length = len(nums) 5 if nums_length == 0: 6 return 0 7 8 dp = [0 for i in range(target+1)] 9 10 dp[0] = 1 #赋初值,代表不选 11 #dp[i]代表给定目标正整数i的组合的个数 12 for i_index in range(1, target+1): 13 for j_index in range(nums_length): 14 if nums[j_index] <= i_index: 15 dp[i_index] = dp[i_index] + dp[i_index-nums[j_index]] 16 17 return dp[-1]
面试题 17.09. 第 k 个数
有些数的素因子只有 3,5,7,请设计一个算法找出第 k 个数。注意,不是必须有这些素因子,而是必须不包含其他的素因子。例如,前几个数按顺序应该是 1,3,5,7,9,15,21。
示例 1:
输入: k = 5 输出: 9
1 class Solution: 2 def getKthMagicNumber(self, k: int) -> int: 3 dp = [1 for _ in range(k)] 4 dp[0] = 1 5 for index in range(1, k): 6 mini = float('inf') 7 for ano_index in range(index): 8 temp3 = 3*dp[ano_index] 9 if 3*dp[ano_index] > dp[index-1]: 10 mini = min(mini, temp3) 11 temp5 = 5*dp[ano_index] 12 if temp5 > dp[index-1]: 13 mini = min(mini, temp5) 14 temp7 = 7*dp[ano_index] 15 if temp7 > dp[index-1]: 16 mini = min(mini, temp7) 17 18 dp[index] = mini 19 20 return dp[k-1]
NC116 把数字翻译成字符串
题目描述
有一种将字母编码成数字的方式:'a'->1, 'b->2', ... , 'z->26'。现在给一串数字,返回有多少种可能的译码结果
输入-"12"
返回值-2
说明--2种可能的译码结果(”ab” 或”l”)
示例2
输入-"31717126241541717"
返回值-192
说明
192种可能的译码结果
dp[i] 表示字符串nums中以i个位置结尾的前缀字符串的解码种数
例如 nums = "123", 此时dp[0]=1,dp[1]=2,dp[2]=3
分类讨论:
当前字符不等于0的时候,dp[i] = dp[i-1],此时将当前位置的一个字符译码
当前字符+前一个字符,记为num, 如果
10<=num<=26
此时符合两个合并一起译码的条件;
若此时i等于1,直接dp[i]++;
大于1, 则dp[i] += dp[i-2];
举个例子: nums = "324"
此时dp[0] = 1, dp[1]呢? dp[2]呢?
很明显nums[1] != '0',所以dp[1] = dp[0],num = 32,此时不满足两个一起译码的条件则循环往下执行,此时 nums[2] != '0',则 dp[2] = dp[1] = 1, num = 24,此时满足两个一起译码的条件,因为i==2大于1,所以dp[2] += dp[2-2] ,dp[2] = 1+1 = 2。
NC92最长公共子序列
题目描述
输入:"1A2C3D4B56","B1D23CA45B6A"
返回值: "123456"
说明
"123456"和“12C4B6”都是最长公共子序列,任意输出一个。
参考:https://blog.csdn.net/hrn1216/article/details/51534607
NC 197 最长公共子串
题目描述
给定两个字符串str1和str2,输出两个字符串的最长公共子串,如果最长公共子串为空,输出-1。
输入
"1AB2345CD","12345EF"
返回值
"2345"
备注:
1 <= |str_1|, |str_2| ≤5000
1 # 2 # longest common substring 3 # @param str1 string字符串 the string 4 # @param str2 string字符串 the string 5 # @return string字符串 6 # 7 class Solution: 8 def LCS(self , str1 , str2 ): 9 # write code here 10 #动态规划复杂度太高 11 # if not str1 or not str2: 12 # return -1 13 # str1_len = len(str1) 14 # str2_len = len(str2) 15 # dp = [[0]*(str2_len+1) for _ in range(str1_len+1)] 16 # max_value = 0 17 18 # for i in range(str1_len): 19 # if str2[0] == str1[i]: 20 # dp[i][0] = 1 21 # if dp[i][0] > max_value: 22 # max_value = dp[i][0] 23 # i_index = i 24 # j_index = 0 25 26 # for j in range(str2_len): 27 # if str1[0]== str2[j]: 28 # dp[0][j] = 1 29 # if dp[0][j] > max_value: 30 # max_value = dp[0][j] 31 # i_index = 0 32 # j_index = j 33 34 # for i in range(str1_len): 35 # for j in range(str2_len): 36 # if str1[i] == str2[j]: 37 # dp[i+1][j+1] = dp[i][j] + 1 38 # if dp[i+1][j+1] > max_value: 39 # max_value = dp[i+1][j+1] 40 # i_index = i+1 41 # j_index = j+1 42 # return str1[i_index-max_value:i_index] 43 if not str1 or not str2: 44 return -1 45 46 str1_len = len(str1) 47 str2_len = len(str2) 48 if str1_len > str2_len: 49 str1, str2 = str2, str1 50 str1_len, str2_len = str2_len, str1_len 51 52 max_len = 0 53 res = '' 54 for i in range(str1_len): 55 if str1[i-max_len:i+1] in str2: 56 res = str1[i-max_len:i+1] 57 max_len += 1 58 if not res: 59 return -1 60 else: 61 return res 62 63 64
NC35最小编辑代价
题目描述
输入:"abc","adc",5,3,2
返回值:2
示例2
输入:"abc","adc",5,3,100
返回值:8
- 1.动态规划:dp[i][j]表示word1的前i个字符编辑成word2的前j个字符需要的最小操作数
- 2.初始状态:dp[i][0] = i,i次删除;dp[0][i] = i,i次插入
- 3.过渡公式:
- 当i字符等于j字符时:dp[i][j] = dp[i-1][j-1],不需要额外操作
- 当i字符不等于j字符时:dp[i][j] = Math.min(insert, delete, replace)
- int insert = dp[i][j-1] + 1; i个编辑成j-1个字符,再插入一个j
- int delete = dp[i-1][j] + 1; i-1个编辑成j个字母,再删除一个i
- int replace = dp[i-1][j-1] + 1; i-1个编辑成j-1个字母,再将i替换成j
NC 字段数字和
题目描述
NC 107 寻找峰值
题目描述
山峰元素是指其值大于或等于左右相邻值的元素。给定一个输入数组nums,任意两个相邻元素值不相等,数组可能包含多个山峰。找到索引最大的那个山峰元素并返回其索引。
假设 nums[-1] = nums[n] = -∞。
示例1
输入
[2,4,1,2,7,8,4]
返回值
5
1 # 2 # 寻找最后的山峰 3 # @param a int整型一维数组 4 # @return int整型 5 # 6 class Solution: 7 def solve(self , a ): 8 # write code here 9 if not a: 10 return 0 11 a_len = len(a) 12 if a_len == 1: 13 return 0 14 15 dp = [False for _ in range(a_len)] 16 dp[0] = True if a[0]> a[1] else False 17 if a[a_len-1] > a[a_len-2]: 18 return a_len-1 19 20 for i in range(1, a_len-1): 21 if a[i-1]<a[i] and a[i+1]<a[i]: 22 dp[i] = True 23 for i in range(a_len-2, -1, -1): 24 if dp[i]: 25 return i 26 return 0