【力扣】1312. 让字符串成为回文串的最少插入次数

【力扣】1312. 让字符串成为回文串的最少插入次数

给你一个字符串 s ,每一次操作你都可以在字符串的任意位置插入任意字符。

请你返回让 s 成为回文串的 最少操作次数 。

「回文串」是正读和反读都相同的字符串。

示例 1:

输入:s = “zzazz”
输出:0
解释:字符串 “zzazz” 已经是回文串了,所以不需要做任何插入操作。
示例 2:

输入:s = “mbadm”
输出:2
解释:字符串可变为 “mbdadbm” 或者 “mdbabdm” 。
示例 3:

输入:s = “leetcode”
输出:5
解释:插入 5 个字符后字符串变为 “leetcodocteel” 。

提示:

1 <= s.length <= 500
s 中所有字符都是小写字母。

class Solution
{
public:
    int minInsertions(string s)
    {
        int len = s.length();
        string s2 = s;
        std::reverse(s2.begin(), s2.end());
        int dp[501][501];
        memset(dp, 0, sizeof(dp));
        for(int i=1; i<=len; i++){
            for(int j=1; j<=len; j++){
                dp[i][j] = s.at(i-1) == s2.at(j-1) ? dp[i-1][j-1] + 1 : std::max(dp[i-1][j],dp[i][j-1]);
            }
        }
        return len - dp[len][len];
    }

};

==================
找到越多的已经有配对的数字,那没有配对的数字就越少,需要插入的次数也就越少。

所以就转化为 找最长的回文子串。

这个题主要考一个转换(把实际问题转换为模板问题)吧

最长的回文子串 转换为 最长相同子序列

将所给的字符串翻转,用翻转后的字符串与字符串来求最长相同子序列。所得子序列的长度,就是原串已有的最长的已经可以对称的数量。

1.凭啥这样转换就是对的。
想象一下,假设这个串是水平的, 有一条竖直的轴,原串已经对称的字母是关于这条轴对称的,没有配对的字母关于这条轴的对称位置用一个空格占位。

以这个轴来进行翻转,已经配对的这些所有字母组成的子序列,和原串中这些字母中组成的子序列是相同的!

也就是 已经配对的字母 和翻转后 这些字母组成的子序列是相同的。

哈哈这个有点绕。

那这样理解,直接把已经配对的子序列s0拿出来,s0一定是对称的吧,就是说s0一定是回文串,当s0跟随原串翻转后,由于这个串是个回文串,s0翻转后还是s0。

等价转换: (get 一下,是不是这个道理)
回文子序列 <=> 所有已配对的字母拼接的子序列

回文子序列 一定是 原串和翻转后的串 的公共子序列

还需要证明 最长的 回文子序列 一定是 最长的 原串和翻转后的串 的公共子序列
或者证明
原串和翻转后的串 的公共子序列 <=> 回文子序列

解题的时候,到这里,就可以直接直接冲一波,凭直觉,两者是等价的,看看能不能过。

哇,暂时想不到,后面再补充吧,有点累了。。。

当然,s2这个变量可以不用写,把s2.at(j-1) 替换成s.at(len-j)。
像这样写是为了更容易理解。

个人认为,在ac的前提下也可以适当增加可读性嘛。可读性高,减小思维负担,出错几率就小很多。

### 解决方案 以下是基于给定引用内容以及专业知识设计的一个完整的 Java 实现来解决 LeetCode 第 125 题——验证回文串。 #### 方法概述 为了判断一个字符串是否为有效的回文串,可以采用双指针方法。该算法通过忽略非字母数字字符并比较两端的字符逐步向中心移动。如果整个过程中未发现不匹配的情况,则认为输入字符串是一个有效回文串[^3]。 下面是具体的代码实现: ```java class Solution { public boolean isPalindrome(String s) { if (s == null || s.isEmpty()) { // 如果字符串为空或者长度为零,返回true return true; } int left = 0; // 定义左指针 int right = s.length() - 1; // 定义右指针 while (left < right) { // 当左指针小于右指针时循环 char lChar = Character.toLowerCase(s.charAt(left)); // 获取左侧字符并转换成小写 char rChar = Character.toLowerCase(s.charAt(right)); // 获取右侧字符并转换成小写 if (!Character.isLetterOrDigit(lChar)) { // 跳过非字母数字字符 left++; continue; } if (!Character.isLetterOrDigit(rChar)) { // 同样跳过右侧的非字母数字字符 right--; continue; } if (lChar != rChar) { // 若两侧字符不同则不是回文串 return false; } left++; // 移动左右指针继续下一轮比较 right--; } return true; // 所有字符均匹配成功,返回true } } ``` 上述代码的时间复杂度为 O(n),其中 n 是字符串 `s` 的长度;空间复杂度为 O(1)[^3]。 --- ### 测试案例分析 对于测试用例 `"A man, a plan, a canal: Panama"`,程序会先移除所有的标点符号并将大写字母转为小写形式得到 `"amanaplanacanalpanama"`。接着利用双指针对比首尾字符直至中间位置无误后确认其为回文串[^4]。 而对于另一个例子如 `"race a car"` ,经过预处理后的结果将是 `"raceacar"` 。由于 'e' 和 'c' 不相等因此最终判定它不是一个合法的回文结构[^2]。 --- ### 注意事项 需要注意的是,在实际应用中可能会遇到极端情况比如超长字符串(最大可达 \(2 \times 10^5\)),所以要确保所选编程环境能够支持如此规模的数据操作而不至于引发性能瓶颈或内存溢出等问题。 此外还需注意边界条件处理,例如当传入空字符串或是仅含特殊符号的情形都应被正确识别为真值情形之一[^1]。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值