问题
给定一个数组,任务是找到数组中的最长递减子数组。如果存在多个长度相同的最长递减子数组,则返回第一个出现的子数组。
例如:对于输入的数组 9 5 4 3 2 5 4 3 2,最长递减子数组是 9 5 4 3 2,因此应输出该子数组。
我的解题思路
要解决这个问题,我们需要遍历数组,找出其中的所有递减子数组,并返回最长的递减子数组。如果存在多个同样长度的最长递减子数组,返回第一个出现的那个。
-
递减子数组的定义:递减子数组是一个子数组,其中每个元素都比它后面的元素小。
-
遍历数组:通过遍历整个数组,比较相邻的元素。如果当前元素比下一个元素大,则当前递减子数组继续增长。如果不满足条件,就更新当前递减子数组的最大长度,并开始一个新的递减子数组。
-
记录最长递减子数组:
- 使用两个变量来跟踪递减子数组的开始和结束位置:
start(当前递减子数组的开始位置)和max_start(最长递减子数组的开始位置),以及max_len(最长递减子数组的长度)。
- 使用两个变量来跟踪递减子数组的开始和结束位置:
-
更新最长子数组:每次递减子数组结束时,检查它的长度,如果长度大于目前记录的最大长度,则更新
max_start和max_len。 -
返回结果:最终返回从
max_start开始,长度为max_len的子数组。
豆包MarsCode AI给出的完善后的思路
-
定义递减子数组:
- 递减子数组是一个元素序列,其中每个元素都严格大于它后面的元素。例如,对于数组
[9, 7, 5, 3],[9, 7, 5, 3]就是一个递减子数组。
- 递减子数组是一个元素序列,其中每个元素都严格大于它后面的元素。例如,对于数组
-
遍历数组:
- 我们可以使用一个遍历数组的方式来检查每个递减子数组。设定两个指针:一个指向当前递减子数组的开始位置(
start),另一个遍历整个数组。
- 我们可以使用一个遍历数组的方式来检查每个递减子数组。设定两个指针:一个指向当前递减子数组的开始位置(
-
关键的操作:
-
当遍历到数组的某个元素时,检查该元素是否小于前一个元素:
-
如果是,则当前递减子数组继续扩展。
-
如果不是,则说明当前递减子数组结束,我们需要:
- 计算当前递减子数组的长度。
- 如果当前递减子数组的长度大于已经记录的最长递减子数组的长度,则更新最大长度和最大子数组的起始位置。
- 将
start更新为当前元素的位置,开始新的递减子数组。
-
-
-
处理最后一个递减子数组:
- 如果数组的最后一部分是递减的,遍历结束时它可能没有被记录。所以我们需要在循环结束后再检查一次最后的递减子数组。
-
返回结果:
- 最终,返回从
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])
时间复杂度分析
-
时间复杂度:
对数组进行了单次遍历,每次只进行常数时间的操作(比如比较、更新变量等)。 因此,遍历数组的时间复杂度是 O(n),其中 n 是数组的长度。
-
空间复杂度:
我们只使用了几个额外的常量空间变量(
max_len,max_start,start),并没有使用额外的数据结构来存储中间结果。 因此,空间复杂度是 O(1) 。
总结
- 这个算法通过单次遍历数组,实时更新当前递减子数组的信息,从而高效地找出最长的递减子数组。
- 时间复杂度是 O(n) ,空间复杂度是 O(1) ,因此非常适合处理大规模数据。