这个系列困扰我很久了,面试又特别爱考,不仅考原题,还特别喜欢在原题的基础上做各种变形。
1.最长上升子序列【不要求连续】
基础:求长度
进阶:求这个子序列/求起始下标
nums = [10,9,2,5,3,7,101,18]
dp = [1] * len(nums)
result = 0
tmp = [[num] for num in nums]
ans = []
start_indices = [i for i in range(len(nums))]
start_idx = 0
for i in range(1, len(nums)):
for j in range(0, i):
if nums[i] > nums[j]:
# dp[i] = max(dp[i], dp[j] + 1)
if dp[i] < dp[j] + 1: # 说明需要更新
dp[i] = dp[j] + 1
tmp[i] = tmp[j] + [nums[i]] # 保存子序列
start_indices[i] = start_indices[j] # 起始下标
if dp[i] > result:
result = dp[i]
ans = tmp[i]
start_idx = start_indices[i]
print(dp,result,ans,start_idx)
# dp=[1,1,1,2,2,3,4,4]
# ans=[2,5,7,101]
2.最长连续上升子序列【连续】
def longest_increasing_subsequence(nums):
if not nums:
return []
n = len(nums)
dp = [1] * n # 用于记录以当前元素为结尾的最长连续上升子序列的长度
for i in range(1, n):
if nums[i] > nums[i - 1]:
dp[i] = dp[i - 1] + 1
# 找到最长连续上升子序列的最后一个元素的索引
max_length = max(dp)
max_index = dp.index(max_length)
# 根据最后一个元素的索引和长度,得到最长连续上升子序列的起始下标
start_index = max_index - max_length + 1
# 根据起始下标和长度,得到最长连续上升子序列本身
longest_sequence = nums[start_index : start_index + max_length]
print(dp,start_index,max_length)
return longest_sequence
# 示例调用
# nums = [1, 3, 2, 4, 5, 7, 6, 8]
nums = [1, 2, 3, 4, 1, 2, 3, 4, 5, 6, 7]
result = longest_increasing_subsequence(nums)
print(result) # 输出: [2, 4, 5, 7]
3.连续子数组的最大和【连续】
def max_subarray_sum(nums):
if not nums:
return []
n = len(nums)
dp = [0] * n
dp[0] = nums[0] # 初始化第一个元素
start_index = end_index = 0 # 记录子数组的起始和结束索引
max_sum = dp[0] # 最大和的初始值
for i in range(1, n):
if dp[i - 1] > 0:
dp[i] = dp[i - 1] + nums[i]
else:
dp[i] = nums[i]
start_index = i # 更新起始索引
if dp[i] > max_sum:
max_sum = dp[i]
end_index = i # 更新结束索引
max_subarray = nums[start_index : end_index + 1]
return max_subarray, max_sum
nums = [-2, 1, -3, 4, -1, 2, 1, -5, 4]
result_subarray, result_sum = max_subarray_sum(nums)
print("具有最大和的连续子数组:", result_subarray)
print("最大和:", result_sum)
3.子序列的最大和【可以不连续】
todo…
4.乘积最大子数组
给你一个整数数组 nums ,请你找出数组中乘积最大的非空连续子数组(该子数组中至少包含一个数字),并返回该子数组所对应的乘积。
子数组 是数组的连续子序列。
输入: nums = [2,3,-2,4]
输出: 6
解释: 子数组 [2,3] 有最大乘积 6。
def func(nums):
if len(nums) <= 1:
return [0, nums[0]][len(nums)]
dp = max_dp = min_dp = nums[0]
for i in range(1, len(nums)):
max_dp = max(max_dp * nums[i], nums[i], min_dp * nums[i])
min_dp = min(max_dp * nums[i], nums[i], min_dp * nums[i])
dp = max(dp, max_dp)
return dp
print(func([2,3,-2,4])) # 6
5.和为k的子数组, 前缀和+哈希表
def func(nums,k):
record = {0: 1}
ans = 0
cur_sum = 0
for n in nums:
cur_sum += n
if (cur_sum - k) in record.keys():
ans += record[cur_sum - k]
record[cur_sum] = record.get(cur_sum, 0) + 1 # get找到了就返回,没找到就是0
return ans
print(func([1,2,3,1,2,3,1,2,3,1,1,1],3)) # 7