leetcode
leetcode 1151 ~ 1200
得到回文串的最少操作次数

得到回文串的最少操作次数

难度:

标签:

题目描述

代码结果

运行时间: 40 ms, 内存: 16.2 MB


/*
 * 思路:
 * 1. 使用双指针法,从字符串的两端向中间遍历。
 * 2. 如果两端字符相同,则移动指针。
 * 3. 如果不同,则需要在左指针右侧或者右指针左侧找到与另一端匹配的字符,
 *    然后交换位置。每次交换位置都计数一次操作次数。
 * 4. 使用Java Stream操作字符串数组。
 * 5. 重复上述步骤,直到字符串变成回文串。
 */
import java.util.stream.IntStream;
import java.util.stream.Collectors;
import java.util.List;
import java.util.Arrays;

public class SolutionStream {
    public int minMovesToMakePalindrome(String s) {
        List<Character> list = s.chars().mapToObj(e -> (char)e).collect(Collectors.toList());
        int left = 0, right = s.length() - 1;
        int moves = 0;
        while (left < right) {
            if (list.get(left) == list.get(right)) {
                left++;
                right--;
            } else {
                int l = right;
                while (l > left && !list.get(l).equals(list.get(left))) {
                    l--;
                }
                if (l == left) { // swap left with left+1
                    swap(list, left, left + 1);
                    moves++;
                } else { // swap list.get(l) to right
                    while (l < right) {
                        swap(list, l, l + 1);
                        l++;
                        moves++;
                    }
                    left++;
                    right--;
                }
            }
        }
        return moves;
    }
    private void swap(List<Character> list, int i, int j) {
        char temp = list.get(i);
        list.set(i, list.get(j));
        list.set(j, temp);
    }
}

解释

方法:

这个题解实现了一个递归的方法来将字符串转换为回文串。首先,检查字符串的第一个字符在字符串中最后一次出现的位置。如果这个字符只出现一次(即在字符串的开始位置),则这个字符是回文中心,需要移动到字符串的中心位置,这将消耗 n/2 次操作(n 是字符串的长度)。否则,如果字符在末尾之前的位置出现,将这个字符通过交换移动到末尾,然后递归地在剩余的子字符串(移除了当前处理的两个字符)上应用同样的过程。继续这个过程直到字符串长度小于或等于2,这时不需要更多的操作。通过逐步将匹配的字符移动到开头和结尾,逐渐构建出回文字符串。

时间复杂度:

O(n^2)

空间复杂度:

O(n^2)

代码细节讲解

🦆
在解法中,为什么当第一个字符只出现一次时,将其移动到字符串中心而不是其他位置?
当第一个字符在字符串中只出现一次,说明它无法与其他字符形成对称的配对,因此它必须成为回文串的中心。回文串的特性是中心对称,所以单个出现的字符适合放在中心位置,以确保左右对称性不被破坏。此外,从效率角度考虑,将其移动到中心也是操作次数最少的方案,因为从任意位置到中心的距离通常小于到端点的距离。
🦆
在代码中,为什么选择从字符串的第一个字符开始查找并处理,而不是从中间或其他位置开始?
从字符串的第一个字符开始处理,可以简化问题的复杂性。这种方法允许我们逐步减小问题的规模,通过每次处理两个对称位置的字符,逐渐向字符串中心推进。从第一个字符开始也有助于在每一步中清楚地定义和解决问题,而从中间或其他位置开始可能会增加处理字符顺序和确定哪些字符需要移动的复杂性。
🦆
当递归处理中间部分的字符串时,移除两端已处理的字符后的新字符串是否总是保证能变成回文串?
在递归处理中,每一步都是基于确保最终字符串成为回文串的目标来设计的。尽管移除两端已处理的字符后的新字符串在当前状态下可能不是回文串,但递归方法确保了通过继续处理可以将其转变为回文串。每一步移除的字符都是对称的,因此理论上剩余的字符串应该是能够通过进一步的操作转换成回文串的。
🦆
如何处理字符串长度为奇数时,中心字符的特殊情况?
当字符串长度为奇数时,中心位置将有一个字符,这个字符是唯一的并且不需要与其他字符配对。在实现中,当遇到这样的字符时,我们通常会检测它是否只出现一次且位于字符串的中心位置。如果是这样,我们不需要对它执行任何操作。如果不是,我们会将其通过最少的操作移动到中心位置。这是确保字符串成为回文的必要步骤,因为中心位置的字符不需要与任何字符配对。

相关问题