1. 项目概述
今天要分享的是一个非常有意思的算法问题——LeetCode 730题"统计不同回文子序列"。这个问题看似简单,但实际解决起来却需要一些巧妙的动态规划技巧。我最近在Qwen3.5-Plus模型上实现了这个算法,过程中积累了不少经验,特别是关于如何高效处理字符串中的回文子序列计数问题。
回文子序列计数是一个经典的动态规划问题,在字符串处理、生物信息学等领域都有广泛应用。这道题的特别之处在于它要求统计"不同"的回文子序列,而不是简单的所有可能。这意味着我们需要考虑去重的问题,使得解决方案更加复杂。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 问题分析与理解
2.1 题目详细解读
题目给定一个字符串s,要求计算其中不同的非空回文子序列的数量。回文子序列是指从字符串中删除0个或多个字符后,剩下的字符序列是回文的(正读反读相同)。例如,字符串"bccb"有以下不同的回文子序列:"b", "c", "bb", "cc", "bcb", "bccb"。
关键点在于:
- 子序列可以不连续
- 相同的回文子序列只计一次
- 空字符串不算作有效子序列
2.2 问题复杂度分析
这个问题看似简单,但暴力解法的时间复杂度极高。对于一个长度为n的字符串,可能的子序列数量是2^n(每个字符都有选或不选两种可能)。即使只考虑回文子序列,直接枚举所有可能性并检查是否为回文也是不可行的。
我们需要找到一个更聪明的方法,利用动态规划来避免重复计算,同时高效地统计不同的回文子序列。
3. 动态规划解决方案设计
3.1 基本思路
动态规划是解决这类计数问题的利器。我们可以定义一个二维数组dp[i][j],表示字符串s从i到j的子串中不同的回文子序列的数量。我们的目标是计算dp[0][n-1],即整个字符串的不同回文子序列数。
关键观察:
- 如果s[i] == s[j],那么我们可以利用内部子问题的解来构建更大的解
- 如果s[i] != s[j],那么解可以由两个较小的子问题的解组合得到
3.2 状态转移方程
定义dp[i][j]为区间[i,j]内不同的回文子序列数:
-
基本情况:
- 当i > j时,dp[i][j] = 0(无效区间)
- 当i == j时,dp[i][j] = 1(单个字符本身就是一个回文)
