(Java) LeetCode 386. Lexicographical Numbers —— 字典序排數
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 —— 字典序排數