1. 程式人生 > >(Java) LeetCode 386. Lexicographical Numbers —— 字典序排數

(Java) LeetCode 386. Lexicographical Numbers —— 字典序排數

break n) leet 一道 lex pac lee 沒有 algo

Given an integer n, return 1 - n in lexicographical order.

For example, given 13, return: [1,10,11,12,13,2,3,4,5,6,7,8,9].

Please optimize your algorithm to use less time and space. The input size may be as large as 5,000,000.


一道沒有標簽的題,第一個想到的思路就是深度優先搜索。很直接的把0-9的數字都想象成節點,每個節點下面又連著0-9的節點。這樣開始從0遍歷到9(除了最開始是從1遍歷),每遇到一個節點就繼續遍歷和它連通的0-9的節點,直到到達n。用圖的思想想這道題非常的簡單,也很清晰。直接上代碼,見解法一。

如果用一個比較大的數觀察一下添加數字的順序,比如112,不難發現一些規律。每次添加完一個數字,下一個數字總是對應著幾種情況(下一個數字一定要比n小):

1. 上次添加過的數字的10倍;

2. 上次添加過的數字+1;

3. 上次添加過的數字除以10(整數除法)+1。

同時這三種情況如果都小於n,那麽總是按照上面的順序依次添加。以112為例,添加完數字1之後,情況1的10,情況2的2,以及情況三的1都符合條件,那麽就要首先添加情況1的10。這樣添加完,下一個需要添加的數字就是基於10而繼續根據情況1,2,3產生的數字。如果情況1不滿足,自然要添加情況2產生的數字。那什麽時候從情況2轉化成情況3呢?通過觀察,從情況2到情況3的轉化永遠發生在個位數為9,或者當上一個添加的數是n的情況。轉化完成之後,繼續按照情況1,2,3的順序添加下一個數字。

總結完規律,只要按規律連續添加n個數即可。見解法二。


解法一(Java)

class Solution {
    public List<Integer> lexicalOrder(int n) {
        List<Integer> res = new ArrayList<>(n);
        for (int i = 1; i <= 9; i++) {
            if (i > n) break;
            dfs(i, res, n);
        }          
        
return res; } private void dfs(int i, List<Integer> res, int n) { res.add(i); for (int m = 0; m <= 9; m++) { if (i * 10 + m > n) break; dfs(i * 10 + m, res, n); } } }

解法二(Java)

class Solution {
    public List<Integer> lexicalOrder(int n) {
        List<Integer> res = new ArrayList<>(n);
        res.add(1);
        int pre = 1;
        for (int i = 1; i < n; i++) {
            if (pre * 10 <= n) pre *= 10;
            else {
                while (pre % 10 == 9 || pre == n) pre /= 10;
                pre++;
            }
            res.add(pre);
        }
        return res;
    }
}

(Java) LeetCode 386. Lexicographical Numbers —— 字典序排數