找出最长的神奇数列
问题描述
问题分析
这道题一开始我是用贪心来解决,先说下贪心和动规的区别,第一篇有提到是局部最优和全局最优,这是核心的。
这道题目标是找到一个符合条件的最长子序列(即长度最大且 0 和 1 交替的子串),如果我们将每个位置的状态和当前最长的“神奇数列”相关联,并通过递推式计算,则可以转化为动态规划问题。这篇帖子既然是动规专题,这里我的解法会使用动态规划,两个解法的代码都会给出。
本题可以归类为最长子序列型动态规划问题的一种变体,与最长递增子序列(LIS) 或 最长公共子序列(LCS) 问题类似。不同的是,本题的状态和转移逻辑与 字符串交替模式 相关,而非数值的单调性或相似性。
与其他动态规划问题的区别
(1)与**最长递增子序列(LIS)**的区别
-
LIS:
- 目标是找到最长的子序列,使得子序列单调递增。
- 每个状态
dp[i]表示以第i个元素结尾的最长递增子序列。 - 状态转移方程:若
nums[j] < nums[i],则dp[i] = max(dp[i], dp[j] + 1)。
-
本题:
- 目标是找到最长子串,使得子串交替由
0和1组成。 - 子串必须是连续的,因此无法像 LIS 一样自由选择元素。
- 目标是找到最长子串,使得子串交替由
(2)与**最长公共子序列(LCS)**的区别
-
LCS:
- 目标是找到两个序列的最长公共子序列。
- 状态定义:
dp[i][j]表示序列A前i个字符与序列B前j个字符的最长公共子序列长度。 - 转移方程:若
A[i] == B[j],则dp[i][j] = dp[i-1][j-1] + 1,否则dp[i][j] = max(dp[i-1][j], dp[i][j-1])。
-
本题:
- 目标是从单一序列中找到满足交替规则的子串。
- 不涉及两个序列之间的匹配,而是针对一个序列的特定模式。
动态规划状态分析
(1)状态定义
-
令
dp[i]表示以位置i为结尾的最长“神奇数列”的长度。- 如果位置
i的字符可以与前一个字符交替,则可以延续子串。 - 否则,从当前字符重新开始计算。
- 如果位置
(2)状态转移方程
-
若
inp[i] != inp[i-1](满足交替规则):dp[i] = dp[i-1] + 1
-
否则:
dp[i] = 1(从当前位置重新开始计算)
(3)边界条件
-
初始状态:
dp[0] = 1,因为以第一个字符为结尾的子串长度为 1。
(4)目标
- 遍历
dp数组,找到最大值max(dp[i]),表示最长的“神奇数列”的长度。
Python代码(贪心)
def solution(inp):
max_length = 0
max_start = 0
for i in range(len(inp)):
# 检查从 i 开始的子序列是否是神奇数列
length = 1
while i + length < len(inp) and inp[i + length] != inp[i + length - 1]:
length += 1
# 如果长度大于等于3,更新最长神奇数列的信息
if length >= 3:
if length > max_length:
max_length = length
max_start = i
# 返回最长的神奇数列
return inp[max_start:max_start + max_length]
if __name__ == "__main__":
# Add your test cases here
print(solution("0101011101") == "010101")
Python代码(DP)
def solution(inp):
n = len(inp)
if n < 3:
return "" # 长度不足3,不可能存在神奇数列
max_length = 0
max_start = 0
i = 0
while i < n:
# 检查从 i 开始是否可以形成神奇数列
length = 1
while i + length < n and inp[i + length] != inp[i + length - 1]:
length += 1
# 更新最长神奇数列的信息
if length >= 3 and length > max_length:
max_length = length
max_start = i
# 移动到下一个可能的起点
i += length # 跳过当前子串
# 如果没有符合条件的神奇数列,返回空字符串
if max_length < 3:
return ""
# 返回最长的神奇数列
return inp[max_start:max_start + max_length]
# 测试用例
print(solution("0101011101")) # 输出 "010101"
print(solution("111010101000")) # 输出 "101010"
print(solution("101010101010")) # 输出 "101010101010"
print(solution("01111")) # 输出 ""