[Leetcode] 267. Palindrome Permutation II

这一题最主要的就是permutation中可自由permute的部分,对于Palindrome而言,前半部分的内容就已经决定了后半部分的内容,所以实质可以自由变换的部分就是前半部分。而对于palindrome而言,前半部分的内容,恰好就是由整体input的字符各取一半组成的。所以基本上,就是从整个input里,取一半的字符(如果字符个数是奇数且能够成为palindrome,多出来的那个非偶数的字符必然就是呆在中间的那个字符),然后排序也好随便也好组成一个新的字符串,并且对这个新的字符串进行permutation,每当一个permutation的结果出来,做镜像得到后半部分的字符串并且组合即可。

这一题的原理不是很复杂,代码就有点长了。因为主要由四步组成
1. 判断输入是否合法(也就是Palindrome Permutation)
2. 构成由半数字符的新字符串
3. permute这个新的字符串
4. 根据permute的结果进行镜像化处理得到最后的结果。

    private boolean checkPalinAndReorderOdd(char[] arr) {
        Map<Character, Integer> charCnt = new HashMap<>();        
        int oddPos = -1;
        for (char ch : arr) {
            charCnt.put(ch, charCnt.getOrDefault(ch, 0) + 1);
        }

        int indx = 0;
        boolean oddMet = false;
        for (char c : charCnt.keySet()) {
            int cnt = charCnt.get(c);
            for (int i = 0; i < cnt / 2; i++) {
                arr[indx] = c;
                indx++;
            }

            if (cnt % 2 != 0) {
                if (!oddMet && arr.length % 2 == 1) {
                    oddMet = true;
                    arr[arr.length / 2] = c;
                } else {
                    return false;
                }
            }
        }
        return true;
    }

    public List<String> generatePalindromes(String s) {
        char[] chArr = s.toCharArray();
        List<String> result = new LinkedList<>();
        if (!checkPalinAndReorderOdd(chArr)) return result;
        permutePalindrome(chArr, 0, result);
        return result;        
    }
    
    private void permutePalindrome(char[] arr, int pos, List<String> result) {
        if (pos >= arr.length / 2) {
            for (int i = 0; i < arr.length / 2; i++) {
                arr[arr.length - 1 - i] = arr[i];
            }
            result.add(new String(arr));
        } else {
            Set<Character> visited = new HashSet<>();
            for (int i = pos; i < arr.length / 2; i++) {
                if (visited.contains(arr[i])) continue;
                swap(arr, i, pos);
                permutePalindrome(arr, pos + 1, result);
                swap(arr, i, pos);
                visited.add(arr[i]);
            }
        }
    }
    
    private void swap(char[] arr, int pos1, int pos2) {
        char tmp = arr[pos1];
        arr[pos1] = arr[pos2];
        arr[pos2] = tmp;
    }

为了假装自己是inplace做的permutation(基于swap),这里的冗余代码真的太多了。自己又写了一个新的版本,performance更好,更简洁一些,相比用重组的字符串直接通过swap做permutation,用更原始的办法,即是一个字符统计器做permutation。代码如下:

    public HashMap<Character, Integer> checkPDAndReorderArr(char[] chArr) {
        HashMap<Character, Integer> chCnt = new HashMap<>();
        for (char c : chArr) chCnt.put(c, chCnt.getOrDefault(c, 0) + 1);
        boolean oddMet = false;
        for (Character c : chCnt.keySet()) {
            if (chCnt.get(c) % 2 == 1 && oddMet) return null;
            else if (chCnt.get(c) % 2 == 1) {
                oddMet = true;
                chArr[chArr.length / 2] = c;
                chCnt.put(c, chCnt.get(c) - 1);
            }
        }
        
        return chCnt;
    }
    
    public List<String> generatePalindromes(String s) {
        char[] chArr = s.toCharArray();
        List<String> result = new LinkedList<>();
        HashMap<Character, Integer> chCnt = checkPDAndReorderArr(chArr);
        if (chCnt == null) return result;
        genPDFromCounts(chCnt, chArr, result, 0);
        return result;
    }
    
    public void genPDFromCounts(HashMap<Character,Integer> chCnt, char[] cache, List<String> result, int cursor) {
        if (cursor >= cache.length / 2) {
            result.add(new String(cache));
        } else {
            for (Character c : chCnt.keySet()) {
                if (chCnt.get(c) == 0) continue;
                cache[cursor] = cache[cache.length - 1 - cursor] = c;
                chCnt.put(c, chCnt.get(c) - 2);
                genPDFromCounts(chCnt, cache, result, cursor + 1);
                chCnt.put(c, chCnt.get(c) + 2);
            }
        }
    }

猜你喜欢

转载自blog.csdn.net/chaochen1407/article/details/81564604