最长递减子数组寻找问题解题思路 | 豆包MarsCode AI刷题

41 阅读4分钟

问题

给定一个数组,任务是找到数组中的最长递减子数组。如果存在多个长度相同的最长递减子数组,则返回第一个出现的子数组。

例如:对于输入的数组 9 5 4 3 2 5 4 3 2,最长递减子数组是 9 5 4 3 2,因此应输出该子数组。

我的解题思路

要解决这个问题,我们需要遍历数组,找出其中的所有递减子数组,并返回最长的递减子数组。如果存在多个同样长度的最长递减子数组,返回第一个出现的那个。

  1. 递减子数组的定义:递减子数组是一个子数组,其中每个元素都比它后面的元素小。

  2. 遍历数组:通过遍历整个数组,比较相邻的元素。如果当前元素比下一个元素大,则当前递减子数组继续增长。如果不满足条件,就更新当前递减子数组的最大长度,并开始一个新的递减子数组。

  3. 记录最长递减子数组

    • 使用两个变量来跟踪递减子数组的开始和结束位置:start(当前递减子数组的开始位置)和max_start(最长递减子数组的开始位置),以及 max_len(最长递减子数组的长度)。
  4. 更新最长子数组:每次递减子数组结束时,检查它的长度,如果长度大于目前记录的最大长度,则更新 max_startmax_len

  5. 返回结果:最终返回从 max_start 开始,长度为 max_len 的子数组。

豆包MarsCode AI给出的完善后的思路

  1. 定义递减子数组

    • 递减子数组是一个元素序列,其中每个元素都严格大于它后面的元素。例如,对于数组 [9, 7, 5, 3][9, 7, 5, 3] 就是一个递减子数组。
  2. 遍历数组

    • 我们可以使用一个遍历数组的方式来检查每个递减子数组。设定两个指针:一个指向当前递减子数组的开始位置(start),另一个遍历整个数组。
  3. 关键的操作

    • 当遍历到数组的某个元素时,检查该元素是否小于前一个元素:

      • 如果是,则当前递减子数组继续扩展。

      • 如果不是,则说明当前递减子数组结束,我们需要:

        1. 计算当前递减子数组的长度。
        2. 如果当前递减子数组的长度大于已经记录的最长递减子数组的长度,则更新最大长度和最大子数组的起始位置。
        3. 将 start 更新为当前元素的位置,开始新的递减子数组。
  4. 处理最后一个递减子数组

    • 如果数组的最后一部分是递减的,遍历结束时它可能没有被记录。所以我们需要在循环结束后再检查一次最后的递减子数组。
  5. 返回结果

    • 最终,返回从 max_start 开始、长度为 max_len 的子数组。

代码实现


def solution(arr: list) -> list:
 
    n = len(arr)
    if n == 0:
        return []

    max_len = 1  # 最长递减子数组的长度
    max_start = 0  # 最长递减子数组的开始位置
    start = 0  # 当前递减子数组的开始位置
    
    for i in range(1, n):
        if arr[i] < arr[i - 1]:  # 当前元素小于前一个元素,递减
            continue
        else:
            # 更新当前递减子数组的长度
            current_len = i - start
            if current_len > max_len:
                max_len = current_len
                max_start = start
            # 重新开始新的递减子数组
            start = i
    
    # 最后一段递减子数组检查
    if n - start > max_len:
        max_start = start
        max_len = n - start
    
    return arr[max_start:max_start + max_len]

# 测试样例
arr1 = [9, 5, 4, 3, 2, 5, 4, 3, 2]
arr2 = [8, 7, 6, 5, 6, 5, 4, 3, 1]
arr3 = [1, 2, 3, 4, 5]



if __name__ == '__main__':
    print(solution(arr=[9, 5, 4, 3, 2, 5, 4, 3, 2]) == [9, 5, 4, 3, 2])
    print(solution(arr=[8, 7, 6, 5, 6, 5, 4, 3, 1]) == [6, 5, 4, 3, 1])
    print(solution(arr=[1, 2, 3, 4, 5]) == [1])

时间复杂度分析

  1. 时间复杂度

    对数组进行了单次遍历,每次只进行常数时间的操作(比如比较、更新变量等)。 因此,遍历数组的时间复杂度是 O(n),其中 n 是数组的长度。

  2. 空间复杂度

    我们只使用了几个额外的常量空间变量(max_lenmax_startstart),并没有使用额外的数据结构来存储中间结果。 因此,空间复杂度是 O(1) 。

总结

  • 这个算法通过单次遍历数组,实时更新当前递减子数组的信息,从而高效地找出最长的递减子数组。
  • 时间复杂度是 O(n) ,空间复杂度是 O(1) ,因此非常适合处理大规模数据。