我正在解决LeetCode问题2193. Minimum Number of Moves to Make Palindrome:

您将看到一个仅由小写英文字母组成的字符串s.

在One move中,您可以 Select s中的任意两个adjacent字符并交换它们.

返回the 101 needed to make s a palindrome.

请注意,将生成输入,以便始终可以将s转换为回文.

我用这个打字代码解决了这个问题:

function minMovesToMakePalindrome(s: string) {
    if (s.length <= 1) return 0;
    if (s[0] === s[s.length - 1]) return minMovesToMakePalindrome(s.slice(1, s.length - 1))
    let leftSwapsCost = s.length;
    let rightSwapsCost = s.length;
    for (let i = 0; i < s.length; i++) {
        if (s[i] === s[0]) {
            // we should swap with the last element
            rightSwapsCost = Math.min(rightSwapsCost, s.length - 1 - i)
        } else if (s[i] === s[s.length - 1]) {
            // we should swap with the first element
            leftSwapsCost = Math.min(leftSwapsCost, i)
        }
    }

    if (leftSwapsCost <= rightSwapsCost) {
        const newString = [s[leftSwapsCost], ...s.slice(1, leftSwapsCost), s[0], ...s.slice(leftSwapsCost + 1)].join('');
        console.log('left: ' + newString + ' cost: ' + leftSwapsCost)
        return leftSwapsCost + minMovesToMakePalindrome(newString.slice(1, s.length - 1))
    } else {
        const newString = [...s.slice(0, s.length - 1 - rightSwapsCost), s[s.length - 1], ...s.slice(s.length - rightSwapsCost, s.length - 1), s[s.length - 1 - rightSwapsCost]].join('');
        console.log('right: ' + newString + ' cost: ' + rightSwapsCost)
        return rightSwapsCost + minMovesToMakePalindrome(newString.slice(1, s.length - 1))
    }
};

基本上,我是在遍历字符数组(字符串),查找与第一个项目相等的项目的索引,然后计算将每个项目与最后一个项目进行交换并将其最小值存储在rightSwapsCost中的成本.

对于与最后一个项目相等的项目也是一样的:我计算将它们与第一个项目交换的最小成本,并将其存储在leftSwapsCost中.

最后,我进行代价最低的交换,并在(交换后获得的)不包含交换前原始字符串的第一个和最后一个元素的新字符串newString上递归调用该函数.

它通过了S="aabb"和S="letelt"的初始测试用例.

但当我提交的时候,它不接受关于S = "eqvvhtcsaaqtqesvvqch"的答案.这很奇怪,因为it did make the string palindrome in less moves than what LeetCode was expecting.

我得到了以下结果:

enter image description here

推荐答案

问题是,你进行了不相邻的掉期交易,错误地估计了它们的成本.这项挑战要求(最低)adjacent个掉期交易.尽管执行非相邻掉期并计算需要多少相邻掉期才能达到同样的结果当然是好的,但这种计算是错误的.

例如,对于示例输入("eqvvhtcsaaqtqesvvqch"),您的算法为交换 Select 索引0("e")和4("h"),并假设此交换的成本为4,但这是错误的.would的成本是4是rotation,它将"h"放在其他4个字符前面,例如从"eqvvH"到"Heqvv"(我故意使用大写来表示旋转的字母),但不是从"EqvvH"到"HqvvE"的交换.然而,这就是您的代码执行的Mutations .但这样的掉期成本大于4!要从"EqvvH"到"HqvvE",您必须进行7次相邻的掉期:

eqvvH
eqvHv
eqHvv
eHqvv
Heqvv
hqEvv
hqvEv
hqvvE

因此,将Mutations 实现为rotations,而不是non-adjacent swaps:

if (leftSwapsCost <= rightSwapsCost) {
    // Fixed:
    const newString = [s[leftSwapsCost], ...s.slice(0, leftSwapsCost), ...s.slice(leftSwapsCost + 1)].join('');
    console.log('left: ' + newString + ' cost: ' + leftSwapsCost)
    return leftSwapsCost + minMovesToMakePalindrome(newString.slice(1, s.length - 1))
} else {
    // Fixed:
    const newString = [...s.slice(0, s.length - 1 - rightSwapsCost), ...s.slice(s.length - rightSwapsCost), s[s.length - 1 - rightSwapsCost]].join('');
    console.log('right: ' + newString + ' cost: ' + rightSwapsCost)
    return rightSwapsCost + minMovesToMakePalindrome(newString.slice(1, s.length - 1))
}

Typescript相关问答推荐

类型脚本如何将嵌套的通用类型展开为父通用类型

创建一个根据布尔参数返回类型的异步函数

类型脚本中没有接口的中间静态类

PrimeNG日历需要找到覆盖默认Enter键行为的方法

返回具有递归属性的泛型类型的泛型函数

被推断为原始类型的交集的扩充类型的交集

在Typescript 中,有没有`index=unfined的速记?未定义:某个数组[索引]`?

Cypress页面对象模型模式.扩展Elements属性

vue-tsc失败,错误引用项目可能无法禁用vue项目上的emit

正确使用相交类型的打字集

使用条件类型的类型保护

如何将对象数组中的键映射到另一种对象类型的键?

垫子工具栏不起作用的Angular 布线

递归生成常量树形 struct 的键控类型

在对象数组中设置值

如何限定索引值必须与相应属性的id字段相同

如何使用 Angular 确定给定值是否与应用程序中特定单选按钮的值匹配?

如何为字符串模板文字创建类型保护

有没有办法从不同长度的元组的联合中提取带有类型的最后一个元素?

将 Angular 从 14 升级到 16 后出现环境变量注入问题