Leetcode - Permutation Sequence

My code:

public class Solution {
    public String getPermutation(int n, int k) {
        if (n <= 0)
            return null;
        int temp = n;
        int total = 1;
        while (temp > 0) {
            total *= temp;
            temp--;
        }
        if (k > total)
            return null;
        boolean[] isVisited = new boolean[n + 1];
        return getResult(n, k, n, isVisited);
    }
    
    private String getResult(int n, int k, int curr, boolean[] isVisited) {
        if (curr <= 1) {
            int temp = 0;
            for (int i = 1; i <= n; i++) {
                if (!isVisited[i]) {
                    temp = i;
                    break;
                }
            }
            return Integer.toString(temp);
        }
        int temp = curr - 1;
        int total = 1;
        while (temp > 0) {
            total *= temp;
            temp--;
        }
        int group = (k - 1) / total + 1; // divide the group
        int count = 0; // count the group including the consideration of visited group
        int begin = 0;
        for (int i = 1; i <= n; i++) {
            if (!isVisited[i]) {
                count++;
                if (count == group)
                    begin = i;
            }
        }
        isVisited[begin] = true;
        String beginStr = Integer.toString(begin);
        k = k - (group - 1) * total;
        return beginStr + getResult(n, k, curr - 1, isVisited);
    }
    
    public static void main (String[] args) {
        Solution test = new Solution();
        System.out.println(test.getPermutation(4, 2));
    }
}

My test result:

Paste_Image.png

這道題目感覺和 Next Permutation 有一些關聯。然后我自己做出來了。
主要就是,按照順序排列后,每一列,都是按照大小排列的。
我可以根據,k, 算出 這個數字所屬的塊,我稱之為,group.
然后,在進入這個group后,還會再分塊,再進入group中的子group。
然后,開頭的字母,都是按照大小順序排列的。
我可以計算出,開頭字母,在這個大group中的偏移位置 group。
然后,這個位置只可能出現 ,1...n,中的一個,然后按照大小排列,第 group 個數字,就是我要的開頭字母。
但是還需要考慮一個情況,就是有些數字已經在之前使用過了。
所以要設置一個布爾數組 isVisited[], 訪問過了就設置為true,下次遍歷,就不再訪問了。
然后就順理成章了。

**
總結: backtracing, Array, 通過布爾數組 isVisted 來避免已經出現的情況再次出現。
**

Anyway, Good luck, Richardo!

My code:

public class Solution {
    public String getPermutation(int n, int k) {
        if (n <= 0 || k <= 0)
            return null;
        /** calculate n! */
        int total = n;
        for (int i = n - 1; i >= 1; i--)
            total *= i;
        StringBuilder ret = new StringBuilder();
        boolean[] isVisited = new boolean[n];
        helper(k, n, n, total, isVisited, ret);
        return ret.toString();
    }
    
    private void helper(int k, int n, int level, int total, boolean[] isVisited, StringBuilder ret) {
        if (level == 1) {
            for (int i = 0; i < n; i++) {
                if (!isVisited[i]) {
                    ret.append(i + 1);
                    break;
                }
            }
            return;
        }
        else {
            total = total / level;
            int group = k / total;
            if (k % total != 0)
                group++;
            int counter = 0;
            for (int i = 0; i < n; i++) {
                if (!isVisited[i]) {
                    counter++;
                    if (counter == group) {
                        ret.append(i + 1);
                        isVisited[i] = true;
                        break;
                    }
                }
            }
            if (k % total == 0)
                k = total;
            else
                k = k % total;
            helper(k, n, level - 1, total, isVisited, ret);
        }
    }
}

這是我寫的版本,比較復雜冗雜。
主要一個問題沒能很好解決。
就是取出一個數字進入字符串后,剩下的以后還得按序選,根據算出來的偏移。
所以我設置了一個boolean[] isVisited來進行這個操作,配合一個計數器,counter
當 counter == 算出來的偏移量后,就取出來放進字符串。
同時,k的更新也是有講究的。反正整體是比較復雜的。下次寫還是不能保證一次通過。
所以參考了網上的代碼,感覺很簡潔,思路也很清晰。

My code:

public class Solution {
    public String getPermutation(int n, int k) {
        if (n <= 0 || k <= 0)
            return null;
        ArrayList<Integer> bag = new ArrayList<Integer>();
        for (int i = 1; i <= n; i++)
            bag.add(i);
        /** calculate n! */
        int total = 1;
        for (int i = 1; i <= n; i++)
            total *= i;
        StringBuilder ret = new StringBuilder();
        k--; // change k to be the index
        while (n > 0) {
            total = total / n;
            int offset = k / total;
            ret.append(bag.get(offset));
            bag.remove(offset);
            k = k % total;
            n--;
        }
        return ret.toString();
    }   
}

這道題木接觸了兩個新東西。

每次取出來一個數后以后不能再取了。可以放在一個list里面,取出來之后就把他刪除了。這樣以后就不會再用到了。然后后面的element會移動到前面,所以可以滿足這么一種效果。

k本來表示的是個數,很多地方用起來很不方便!需要分類討論。但是k-- 把他改成index之后,所有的都變方便了,不需要再把代碼寫的和之前一樣的復雜了。妙!

參考網頁:
http://www.programcreek.com/2013/02/leetcode-permutation-sequence-java/

Anyway, Good luck, Richardo!

My code:

public class Solution {
    public String getPermutation(int n, int k) {
        List<Integer> bag = new ArrayList<Integer>();
        for (int i = 1; i <= n; i++) {
            bag.add(i);
        }
        
        int total = 1;
        for (int i = 1; i <= n; i++) {
            total *= i;
        }
        
        StringBuilder ret = new StringBuilder();
        k--;
        while (n > 0) {
            total = total / n;
            int offset = k / total;
            int digit = bag.get(offset);
            ret.append(digit);
            bag.remove(offset);
            
            k = k % total;
            n--;
        }
        
        return ret.toString();
    }
}

沒做出來。雖然思路還是和以前一樣。
主要的一個問題還是 offset 和 真是的位置一直分不清楚。雖然我也想到了 k--

首先k--, 將它轉換為index,之后再做。
還有個操作就是用list存 1-9,用一個刪除一個,這樣后面的可以靠過來。雖然這么做開銷挺大,但考慮到一共是 1-9,可以默認,開銷為O(1)

Anyway, Good luck, Richardo! -- 09/05/2016

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容