子序列/子数组系列

这个系列困扰我很久了,面试又特别爱考,不仅考原题,还特别喜欢在原题的基础上做各种变形。

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
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值