解题思路

本题的核心在于回文串只需确定左半部分,右半部分由左半部分对称得到。因此问题转化为:用 s 中一半的字符(各取一半)构造一个长度为 n/2 的字符串,使其对应的完整回文串严格大于 target。

解题分两步:

1. 可行性校验:统计 s 中字符频次,若出现奇数次的字符超过 1 个,则无法构成回文,直接返回空串。
2. 贪心构造左半部分:
   · 先尝试让左半部分与 target 左半部分完全一致,然后检查构造出的完整回文串是否大于 target。若是,直接返回。
   · 若不行,从右向左找到第一个可以增大的位置,填入比 target 对应位置稍大的字符,该位置之后的字符按字典序最小填充(即从小到大填入剩余字符)。

---

Java 代码实现

```java
class Solution {
    public String lexPalindromicPermutation(String s, String target) {
        int n = s.length();
        int half = n / 2;

        // 1. 统计 s 中字符频次
        int[] cnt = new int[26];
        for (char c : s.toCharArray()) cnt[c - 'a']++;

        // 2. 检查能否构成回文:奇数频次字符不能超过 1 个
        int oddChar = -1;
        for (int i = 0; i < 26; i++) {
            if (cnt[i] % 2 == 1) {
                if (oddChar != -1) return "";
                oddChar = i;
            }
        }

        // 3. 左半部分可用字符:每个字符取一半
        int[] leftCnt = new int[26];
        for (int i = 0; i < 26; i++) leftCnt[i] = cnt[i] / 2;

        // 4. 贪心构造左半部分
        int[] left = new int[half];
        int[] remain = leftCnt.clone();

        // 4a. 先尝试完全匹配 target 的左半部分
        boolean match = true;
        for (int i = 0; i < half; i++) {
            int c = target.charAt(i) - 'a';
            if (remain[c] > 0) {
                left[i] = c;
                remain[c]--;
            } else {
                match = false;
                break;
            }
        }

        if (match) {
            // 完全匹配成功,构造完整回文串检查是否大于 target
            String candidate = buildPalindrome(left, remain, oddChar, n);
            if (candidate.compareTo(target) > 0) return candidate;
        }

        // 4b. 从右向左找第一个可以增大的位置
        for (int pos = half - 1; pos >= 0; pos--) {
            // 重置剩余计数
            remain = leftCnt.clone();
            int[] tempLeft = new int[half];
            boolean ok = true;

            // 填充 pos 之前的位置,与 target 一致
            for (int i = 0; i < pos; i++) {
                int c = target.charAt(i) - 'a';
                if (remain[c] > 0) {
                    tempLeft[i] = c;
                    remain[c]--;
                } else {
                    ok = false;
                    break;
                }
            }
            if (!ok) continue;

            // 在 pos 位置填入比 target[pos] 大的最小字符
            int targetChar = target.charAt(pos) - 'a';
            boolean found = false;
            for (int c = targetChar + 1; c < 26; c++) {
                if (remain[c] > 0) {
                    tempLeft[pos] = c;
                    remain[c]--;
                    found = true;
                    break;
                }
            }
            if (!found) continue;

            // pos 之后的位置填入剩余字符的最小字典序
            for (int i = pos + 1; i < half; i++) {
                for (int c = 0; c < 26; c++) {
                    if (remain[c] > 0) {
                        tempLeft[i] = c;
                        remain[c]--;
                        break;
                    }
                }
            }

            // 构造完整回文串并检查
            String candidate = buildPalindrome(tempLeft, remain, oddChar, n);
            if (candidate.compareTo(target) > 0) return candidate;
        }

        return "";
    }

    // 根据左半部分构造完整回文串
    private String buildPalindrome(int[] left, int[] remain, int oddChar, int n) {
        int half = n / 2;
        StringBuilder sb = new StringBuilder();

        // 左半部分
        for (int i = 0; i < half; i++) sb.append((char)(left[i] + 'a'));

        // 中间字符(仅当 n 为奇数)
        if (n % 2 == 1) sb.append((char)(oddChar + 'a'));

        // 右半部分 = 左半部分反转
        for (int i = half - 1; i >= 0; i--) sb.append((char)(left[i] + 'a'));

        return sb.toString();
    }
}
```

---

复杂度分析

指标 复杂度
时间复杂度 O(n × 26) ≈ O(n),其中 n 为字符串长度,字符集大小为 26
空间复杂度 O(n)(存储左半部分数组和结果字符串)

 

Logo

汇聚全球AI编程工具,助力开发者即刻编程。

更多推荐