新手求助:整数序列中提取有序等差子序列的练习卡壳
搞定这个等差升序子序列问题!(新手友好版)
兄弟我懂这种卡壳到挠头的感觉!当初我刚摸编程的时候,也在这种看似“简单”的题上耗了快一下午,别灰心咱们一步步拆解,肯定能搞定~
首先先明确问题:从给定整数序列里,找出元素递增、相邻差值固定,且长度尽可能长的子序列(从你的示例来看,应该是要长度≥3的,不然像[1,4]这种差值3的也符合,但示例没输出)。如果是要连续的等差子序列(就像示例里的4,5,6,7那样连续),那解法会更简单,我先讲这个新手最容易理解的版本,再拓展到非连续的情况。
一、连续等差子序列解法(O(n)效率,超易懂)
思路拆解
- 特殊情况先处理:如果输入序列长度小于3,直接返回空(因为凑不出长度≥3的等差子序列)
- 遍历序列找连续段:从第二个元素开始,记录当前连续等差段的差值和元素,一旦遇到差值变化,就对比当前段和之前记录的最长段,更新最长段,然后重置当前段
- 最后收尾检查:遍历结束后,别忘了再检查一次最后一段的长度,避免漏掉
代码示例(Python)
def find_longest_consecutive_arithmetic_subsequence(nums): n = len(nums) if n < 3: return [] # 初始化最长子序列和当前子序列 longest_subseq = [] current_subseq = [nums[0], nums[1]] current_diff = nums[1] - nums[0] for i in range(2, n): # 如果当前元素和前一个的差值和当前段差值一致,加入当前段 if nums[i] - nums[i-1] == current_diff: current_subseq.append(nums[i]) else: # 对比更新最长子序列(只保留长度≥3的) if len(current_subseq) > len(longest_subseq) and len(current_subseq) >= 3: longest_subseq = current_subseq.copy() # 重置当前段为新的起始 current_subseq = [nums[i-1], nums[i]] current_diff = nums[i] - nums[i-1] # 最后检查一次当前段,避免最后一段是最长的但没更新 if len(current_subseq) > len(longest_subseq) and len(current_subseq) >= 3: longest_subseq = current_subseq return longest_subseq # 测试你的示例 input_nums = [1,4,5,6,7,10] print(find_longest_consecutive_arithmetic_subsequence(input_nums)) # 输出 [4,5,6,7]
二、非连续等差子序列解法(通用版)
如果你的需求是子序列可以不连续(比如输入[1,3,5,2,4,6],要返回[1,3,5]或[2,4,6]),那可以用暴力遍历的方法(新手易懂),或者进阶用动态规划优化效率。
暴力遍历版思路
- 遍历所有可能的起始两个元素,计算它们的差值
- 顺着这个差值往后找,把符合的元素加入当前子序列
- 每次找到子序列后,和当前最长子序列对比,保留更长的那个
暴力版代码示例
def find_longest_arithmetic_subsequence(nums): n = len(nums) if n < 3: return [] longest_subseq = [] # 遍历所有起始的两个元素对 for i in range(n): for j in range(i + 1, n): diff = nums[j] - nums[i] current_subseq = [nums[i], nums[j]] next_num = nums[j] + diff # 往后找符合差值的元素 k = j + 1 while k < n: if nums[k] == next_num: current_subseq.append(nums[k]) next_num += diff k += 1 # 更新最长子序列(只保留长度≥3的) if len(current_subseq) > len(longest_subseq) and len(current_subseq) >= 3: longest_subseq = current_subseq return longest_subseq # 测试示例 input_nums = [1,4,5,6,7,10] print(find_longest_arithmetic_subsequence(input_nums)) # 输出 [4,5,6,7]
动态规划优化版(进阶)
暴力版效率是O(n³),如果序列很长会很慢,用动态规划可以降到O(n²):用dp[i][d]表示以第i个元素结尾、差值为d的等差子序列长度,遍历每个元素时,和前面所有元素对比计算差值,更新dp数组,同时记录最长的子序列。
def find_longest_arithmetic_subsequence_dp(nums): n = len(nums) if n < 3: return [] # dp[i]是字典,key是差值,value是对应子序列长度 dp = [{} for _ in range(n)] max_len = 2 result = [] for i in range(n): for j in range(i): diff = nums[i] - nums[j] # 如果j位置有相同差值的子序列,长度+1,否则初始为2 dp[i][diff] = dp[j].get(diff, 2) # 更新最长子序列 if dp[i][diff] > max_len: max_len = dp[i][diff] # 回溯找到完整子序列 current_subseq = [nums[i]] current_num = nums[i] - diff k = j while k >= 0 and nums[k] == current_num: current_subseq.insert(0, current_num) current_num -= diff # 找前一个元素的位置 for m in range(k-1, -1, -1): if nums[m] == current_num: k = m break else: break result = current_subseq return result if max_len >= 3 else [] # 测试示例 input_nums = [1,4,5,6,7,10] print(find_longest_arithmetic_subsequence_dp(input_nums)) # 输出 [4,5,6,7]
小提醒
如果题目明确要求是连续的子序列,优先用第一个方法,简单高效;如果允许非连续,再根据序列长度选暴力版或动态规划版。
慢慢来,新手遇到这种问题很正常,多调试几次代码,看着输出一步步找问题,很快就能掌握啦!
内容的提问来源于stack exchange,提问作者PS.
相关产品推荐
相关产品推荐

