C语言/数据结构动态规划题解:字符串变回文的最少操作次数——最长回文子序列(LPS)

问题描述

小明正在玩一个字符串拼图游戏,他有一个由小写字母组成的字符串。游戏规则允许他进行两种操作:1) 删除任意一个字符;2) 在任意位置插入任意一个小写字母。每次操作都会消耗1点能量。现在小明想要通过最少的操作次数,使得字符串变成回文串(即正着读和反着读都一样)。请你帮助小明计算最少需要多少次操作。

要求:

  1. 设计一个动态规划算法来计算最小操作次数。
  2. 算法的时间复杂度应为 O(n²),其中 n 是字符串的长度。

提示 :

最小操作次数等于字符串长度减去该字符串的最长回文子序列的长度。

例如,字符串 "abcda" 的最长回文子序列是 "aca" 或 "ada",长度为3,所以最小操作次数为 5 - 3 = 2。

你可以使用动态规划来求解最长回文子序列的长度。

测试样例

样例1:

输入:s = "abcda" 输出:2 解释:最长回文子序列为 "aca" 或 "ada",长度为3,所以最小操作次数为 5 - 3 = 2。一种可行方案是删除 'b' 和 'c'(2次操作)得到 "ada"。

样例2:

输入:s = "abcd" 输出:3 解释:最长回文子序列为 "a"(或 "b"、"c"、"d"),长度为1,所以最小操作次数为 4 - 1 = 3。一种可行方案是删除 'b'、'c'、'd'(3次操作)得到 "a"。

样例3:

输入:s = "a" 输出:0 解释:单个字符已经是回文串,最长回文子序列长度为1,所以最小操作次数为 1 - 1 = 0。

约束条件

  • 1 ≤ s.length ≤ 1000
  • 字符串 s 仅包含小写英文字母
  • 保证输入字符串非空

程序代码

#include <stdio.h>

#include <string.h>

int minOperations(char* s) {

int n = strlen(s);

if (n <= 1) return 0;

// dpij 表示 si..j 的最长回文子序列长度

int dp10001000;

// 初始化:单个字符长度为1

for (int i = 0; i < n; i++) {

dpii = 1;

}

// 按长度递增计算

for (int len = 2; len <= n; len++) {

for (int i = 0; i + len - 1 < n; i++) {

int j = i + len - 1;

if (si == sj) {

if (len == 2) {

dpij = 2;

} else {

dpij = dpi+1j-1 + 2;

}

} else {

dpij = (dpi+1j > dpij-1) ? dpi+1j : dpij-1;

}

}

}

int lps = dp0n-1;

return n - lps;

}

int main() {

printf("%d\n", minOperations("abcda")); // 2

printf("%d\n", minOperations("abcd")); // 3

printf("%d\n", minOperations("a")); // 0

return 0;

}

cpp 复制代码
#include <stdio.h>
#include <string.h>

int minOperations(char* s) {
    int n = strlen(s);
    if (n <= 1) return 0;
    
    // dp[i][j] 表示 s[i..j] 的最长回文子序列长度
    int dp[1000][1000];
    
    // 初始化:单个字符长度为1
    for (int i = 0; i < n; i++) {
        dp[i][i] = 1;
    }
    
    // 按长度递增计算
    for (int len = 2; len <= n; len++) {
        for (int i = 0; i + len - 1 < n; i++) {
            int j = i + len - 1;
            
            if (s[i] == s[j]) {
                if (len == 2) {
                    dp[i][j] = 2;
                } else {
                    dp[i][j] = dp[i+1][j-1] + 2;
                }
            } else {
                dp[i][j] = (dp[i+1][j] > dp[i][j-1]) ? dp[i+1][j] : dp[i][j-1];
            }
        }
    }
    
    int lps = dp[0][n-1];
    return n - lps;
}

int main() {
    printf("%d\n", minOperations("abcda"));  // 2
    printf("%d\n", minOperations("abcd"));   // 3
    printf("%d\n", minOperations("a"));      // 0
    return 0;
}

运行结果

相关推荐
_wxd6661 小时前
二叉搜索树(BST)万字详解:概念、操作、性能分析与 C++ 实现
数据结构·c++·二叉搜索树
UIU1141 小时前
P1115 最大子段和
c++·算法
垆边人似月.1 小时前
华为题:零钱兑换
算法·华为
wuminyu1 小时前
ZGC染色指针在虚拟线程stackChunkOop上的并发屏障全景分析
java·linux·c语言·jvm·c++
Logic1012 小时前
C语言/数据结构组合数学题解:数字好排列计数——质数倍数分类与阶乘取模
c语言·数据结构·算法·组合数学·时间复杂度·排列·取模运算
碧海银沙音频科技研究院2 小时前
炬芯ATS3089智能手表烧录方法
人工智能·驱动开发·嵌入式硬件·算法
维克兜率天2 小时前
【维克】统计套利:寻找市场的“定价误差“
人工智能·python·算法
aqiu1111112 小时前
【C++算法打怪专栏】LeetCode 1. 两数之和(哈希表解法总结)
c++·算法·leetcode
楚识科技2 小时前
票据 OCR 识别技术深度解析:从算法原理到企业级落地实现
算法·ocr