满足和/积的子数组
leecode713,乘积小于k的子数组。滑动窗口,双指针。考虑清楚边界条件。
class Solution: def numSubarrayProductLessThanK(self, nums, k) -> int: s = e = 0 tmp = nums[0] ans = 0 while s < len(nums) and e < len(nums): if tmp <k: ans += e-s+1 if e<len(nums)-1: e += 1 tmp *= nums[e] else: break else: while s<e and s<len(nums)-1 and tmp >= k: tmp /= nums[s] s += 1 if tmp>=k and s == e and e < len(nums)-1: e += 1 tmp *= nums[e] if e == len(nums) -1 and s == e and tmp >= k: break return ans if __name__ == "__main__": solution = Solution() nums = [1,2,3] k = 0 ans = solution.numSubarrayProductLessThanK(nums,k) print(ans)
leecode560,和为k的子数组,前缀和(连续和)+哈希表(空间换时间),注意前缀和以及哈希表的构建更新顺序。
import collections class Solution: def subarraySum(self, nums, k: int) -> int: prefix = [0]*len(nums) tmp = 0 hash_table = collections.defaultdict(int) hash_table[0] = 1 ans = 0 for i in range(len(nums)): tmp += nums[i] prefix[i] = tmp ans += hash_table[prefix[i]-k] hash_table[tmp] += 1 return ans if __name__ == "__main__": solution = Solution() nums = [1] k = 0 ans = solution.subarraySum(nums,k) print(ans)
leecode1,两数字之和,哈希表(空间换时间),注意哈希表的更新顺序。
class Solution: def twoSum(self, nums: List[int], target: int) -> List[int]: hash_table = {} for i in range(len(nums)): if target - nums[i] in hash_table: return [i,hash_table[target - nums[i]]] hash_table[nums[i]] = i
leecode15,三数字之和,排序+双指针
class Solution: def threeSum(self, nums: List[int]) -> List[List[int]]: n = len(nums) nums.sort() ans = [] for first in range(n): if first > 0 and nums[first] == nums[first-1]: continue third = n - 1 target = -nums[first] for second in range(first+1,n): if second > first + 1 and nums[second] == nums[second - 1]: continue while second < third and nums[second] + nums[third] > target: third -= 1 if second == third: break if nums[second] + nums[third] == target: ans.append([nums[first],nums[second],nums[third]]) return ans
leecode653,两树之和(输入二叉搜素树),中序遍历+双指针
class Solution: def findTarget(self, root: Optional[TreeNode], k: int) -> bool: self.ans = [] def morder(root): if root == None: return morder(root.left) self.ans.append(root.val) morder(root.right) return morder(root) s = 0 e = len(self.ans)-1 while s < e: if self.ans[s] + self.ans[e] == k: return True elif self.ans[s] + self.ans[e] > k: e -= 1 else: s += 1 return False
leecode167,两数之和(输入有序数组),双指针
class Solution: def twoSum(self, numbers: List[int], target: int) -> List[int]: self.ans = numbers k = target s = 0 e = len(self.ans)-1 while s < e: if self.ans[s] + self.ans[e] == k: return [s+1,e+1] elif self.ans[s] + self.ans[e] > k: e -= 1 else: s += 1
leecode724,寻找数组的中心下表(左右元素和相等),优化前缀和+后缀和
class Solution: def pivotIndex(self, nums: List[int]) -> int: suffix = [0]*(len(nums)+1) tmp = 0 for i in range(len(nums)-1,-1,-1): tmp += nums[i] suffix[i] = tmp prefix = 0 for i in range(len(nums)): if prefix == suffix[i+1]: return i prefix += nums[i] return -1
最()子序列
leecode1143,最长公共子序列,动态规划,可以优化空间,但是要特别注意优化空间后转移方程的书写,用dp[]存储上一行的状态,用dp_1存储当前状态,极限优化空间可以根据len(text1)和len(text2)的大小来交换text1和text2;可以用递归来写,但是要注意记忆化搜索,注意自顶向下递归。
class Solution: def longestCommonSubsequence(self, text1: str, text2: str) -> int: dp = [[0]*(len(text2) + 1) for _ in range(len(text1) + 1)] for i in range(1,len(text1)+1): for j in range(1,len(text2)+1): if text1[i-1] == text2[j-1]: dp[i][j] = dp[i-1][j-1] + 1 else: dp[i][j] = max(dp[i][j-1],dp[i-1][j]) return dp[len(text1)][len(text2)] ## 优化空间版本 class Solution: def longestCommonSubsequence(self, text1: str, text2: str) -> int: dp = [0]*(len(text2)+1) dp_1 = 0 for i in range(1,len(text1)+1): dp_1 = 0 for j in range(1,len(text2)+1): if text1[i-1] == text2[j-1]: dp[j-1],dp_1 = dp_1,dp[j-1] + 1 else: dp[j-1],dp_1 = dp_1,max(dp_1,dp[j]) dp[len(text2)] = dp_1 return dp_1 ## 递归版本 class Solution: def longestCommonSubsequence(self, text1: str, text2: str) -> int: @lru_cache(None) def dfs(i,j): if i == 0 or j== 0: return 0 if text1[i-1] == text2[j-1]: return dfs(i-1,j-1) +1 else: return max(dfs(i-1,j),dfs(i,j-1)) return dfs(len(text1),len(text2))
leecode128,最长连续序列,哈希表+判断优化,判断num-1是否出现过,对于连续的序列,只计算最开头的那一次
class Solution: def longestConsecutive(self, nums) -> int: ans = 0 hash_table = set(nums) for num in nums: if num - 1 not in hash_table: tmp = num + 1 tmp_ans = 1 while tmp in hash_table: tmp_ans += 1 tmp += 1 ans = max(ans,tmp_ans) return ans
offer93,最长斐波那契数列,动态规划+哈希表+判断优化,注意这里没有重复元素,所以第三元素的判断可以用哈希表,否则有重复元素的存在的时候就不能用哈希表存。
class Solution: def lenLongestFibSubseq(self, arr: List[int]) -> int: indices = {x:i for i,x in enumerate(arr)} ans = 0 dp = [[0] * len(arr) for _ in range(len(arr))] for i,x in enumerate(arr): for j in range(i-1,-1,-1): if arr[j]*2 <= arr[i]: break if x - arr[j] in indices: k = indices[x-arr[j]] dp[j][i] = max(3,dp[k][j] + 1) ans = max(dp[j][i],ans) return ans
offer1027,最长等差数列,动态规划,和offer93类似,但是不能用哈希表来存第三个元素,因为数组有重复元素,本题遍历第一个元素和公差,dp[i][j]代表以nums[i]结尾的公差为j的等差数列的长度,因为公差可能为负数,因此要特殊处理,同时加上某个值使其变非负。
class Solution: def longestArithSeqLength(self, nums) -> int: n = len(nums) ans = 0 div = max(nums) - min(nums) dp = [[1]*(div*2+1) for _ in range(n)] for i in range(1,n): for k in range(i): j = nums[i] - nums[k] + div dp[i][j] = max(dp[i][j],dp[k][j] + 1) ans = max(ans,dp[i][j]) return ans