leetcode 767 重构字符串

题目描述

给定一个字符串,将字符串重新排列,使得任意相邻两个字符不同。若无法重构,返回空串。字符串中只含小写字母。

思路

该题是典型的贪心法。贪心法要求每一步都仅考虑当前局部最优解。那么对于该字符串将其中每个字符统计出现次数,之后按次数依次考虑每个字符的摆放位置即可。

想要相邻字符不相同,必须将相同字符间隔摆放。由此可知,当出现次数最多的字符数量超过字符串的一半以上,则必然无法重构。因为即便只间隔一位摆放该字符,也无法使得该字符不相邻。

重构

若出现次数最多的字符数量不足字符串长度一半,这时重构该字符串的方法如下:

先统计所有字符出现次数,然后遍历每个字符,对每个字符,按其出现次数进行摆放。设置奇偶指针,两个指针指向了下一个可放置字符的位置,初始值为1,0(因为相邻字符不相同,所以同一个字符要么都放在奇指针位置,要么都在偶指针位置)

1.若出现次数不超过字符串长度一半,且奇指针位置未超过字符串长度,那么当前字符放置在奇指针位置。奇指针向后走两步。

2.否则将该字符放在偶指针位置,偶指针向后走两步。

当1执行完毕时,所有奇数下标均已放置完毕,再执行2,放置偶数下标。

重构策略证明

只有一种情况比较模糊,即当某个字符放置完奇数位,还剩余字符,那么必将放置在偶数位,它是否有可能和奇数位的自己相邻?答案是否定的。
该字符的最小奇数下标和最大偶数下标差值不小于3,具体证明可参考Leetcode767官方题解。

c++代码:

class Solution {
public:
    string reorganizeString(string S) {
        if (S.length() <= 2)
        return S;
        vector<int> count(26,0);
        int maxCount = 0;
        int length = S.length();
        for (int i = 0;i < length;i++){
            count[S[i] - 'a']++;
            maxCount = max(maxCount,count[S[i] - 'a']);
        }
        if (maxCount > (length + 1) / 2)
        return "";
        string res(length,' ');
        int oddIndex = 1,evenIndex = 0;
        for (int i = 0;i < 26;i++){
            char c = i + 'a';
            while(count[i] > 0 && count[i] <= length / 2 && oddIndex < length){
                res[oddIndex] = c;
                count[i]--;
                oddIndex += 2;
            }
            while(count[i] > 0){
                res[evenIndex] = c;
                count[i]--;
                evenIndex += 2;
            }
        }
        return res;
    }
};

你可能感兴趣的:(刷题,字符串,指针,算法,leetcode)