【刷題日記】leetcode-767 重構字串

焜說發表於2020-12-01

一、題目

給定一個字串S,檢查是否能重新排布其中的字母,使得兩相鄰的字元不同。
若可行,輸出任意可行的結果。若不可行,返回空字串。
示例 1:
輸入: S = “aab”
輸出: “aba”
示例 2:
輸入: S = “aaab”
輸出: “”
注意:
S 只包含小寫字母並且長度在[1, 500]區間內。

二、解題

思路:

  1. “兩相鄰的字元不同” 推出重複次數最多的字元不能超過n/2 + 1 個,否則不能構成符合條件的字串
  2. 生成雜湊表,記錄每個字元出現的個數,將最大字元(X)從雜湊表剔除
  3. 如果滿足條件,遍歷雜湊表,將X放在遍歷開頭加入,直到除X外的所有字元都追加完成
  4. 此時若還有X沒有追加到重構的字串裡,從重構的字串尾部判斷是否能追加插入X

另外,題目說了是純字母的,可以通過轉成int陣列來解決。效能上應該能提升不少。習慣用通用解法,這裡編碼的時候就麼有寫。

按這個思路,其實自己覺得應該能挺快的。結果雖然不會超時,但是還是算不上一個好的解法:
在這裡插入圖片描述
程式碼如下:

class Solution {
    public String reorganizeString(String S) {
        // 將輸入拆分為字元陣列
        String[] cArr = S.split("");

        // 確定閾值
        int origLength = S.length();
        int max = origLength / 2 ;
        if(origLength % 2 == 1) {
            max = max + 1;
        }

        // 遍歷確定各元素個數
        Map<String, Integer> hash = new HashMap<>();
        int maxLength = 0;
        // 用於記錄最大的key
        String maxKey = cArr[0];
        for(int i = 0; i < cArr.length; ++i) {
            int currentSize = hash.getOrDefault(cArr[i], 0) + 1;
            if(maxLength < currentSize) {
                maxLength = currentSize;
                maxKey = cArr[i];
            }
            hash.put(cArr[i], currentSize);
        }

        // 校驗是否滿足要求
        if(maxLength > max) {
            return "";
        }

        // 如果沒有溢位, 則生成符合要求的字串
        // 將最大的key作為開始,遍歷所有元素生成滿足要求的字串
        String maxKeyStr = maxKey;
        char maxKeyChar = maxKey.charAt(0);
        hash.remove(maxKeyStr);
        String ret = "";
        while(origLength-- > 0 && maxLength-- > 0) {
            ret = ret+maxKey;
            for(Map.Entry<String, Integer> entry : hash.entrySet()) {
                if(entry.getValue() > 0) {
                    ret = ret + entry.getKey();
                    entry.setValue(entry.getValue() - 1);
                    origLength--;
                }
            }
            // 如果hash裡的字母都寫完了,退出
            if(origLength == maxLength) {
                break;
            }
        }

        // 遍歷完尚未清空最大陣列,將剩餘的maxKey插入結果中
        StringBuilder sbRet=new StringBuilder(ret);
        if(maxLength > 0) {
            int i = 0;
            while(maxLength-- > 0) {
                // 如果插入位置左右都沒有maxKey,則後續都可以直接插入
                while((i == 0 && sbRet.charAt(ret.length() - 1 - i) == maxKeyChar)
                        || (i > 0 && (sbRet.charAt(ret.length() - 1 - i) == maxKeyChar || sbRet.charAt(ret.length() - 1 - i + 1) == maxKeyChar))) {
                    i++;
                }
                sbRet.insert(ret.length() - i++, maxKey);
            }
        }
        return sbRet.toString();
    }
}

三、題解

有些題解說先把X放在下標偶數位置,再隨意安插其他字元就可以得出解了,但是如果是aaaabbbbc這種,a_a_a_a_這樣安插完後,再隨意安插的話就有abacababb,會出現重複的情況,這個還沒有get到題解的意思。

另外官方題解:重構字串看著可以說是比較權威了,值得研讀,先休息,明天學習下題解。

相關文章