386:字典序排數 (中等)
給定一個整數 n, 返回從 1 到 n 的字典順序。
例如,
給定 n =1 3,返回 [1,10,11,12,13,2,3,4,5,6,7,8,9] 。
請儘可能的優化算法的時間複雜度和空間複雜度。 輸入的數據 n 小於等於 5,000,000。
來源:力扣(LeetCode)
思路:
剛開始看到這個題目,主要是不太清楚什麼是字典序
看下圖:每一個節點都擁有 10 個孩子節點,因爲作爲一個前綴 ,它後面可以接 0~9 這十個數字。整個字典序排列也就是對十叉樹進行先序遍歷。1, 10, 100, 101, … 11, 110 …
字典序 簡而言之,就是根據數字的前綴進行排序,
比如 10 < 9,因爲 10 的前綴是 1,比 9 小。
再比如 112 < 12,因爲 112 的前綴 11 小於 12
假設n=111
1,10,100,每次都乘以 10
100,101,102,…,109,每次加 1
109,19,99,末尾爲 9 則先除以 10 直到末尾不爲 9 再加 1
111,排到 n 了則先除以 10 再加 1
代碼實現
public List<Integer> lexicalOrder(int n) {
List<Integer> list = new ArrayList<>();
int num = 1;
list.add(1);
for(int i = 1;i<n;i++) {
if(num*10 <=n) {
num*=10;
list.add(num);
}
else {
while(num%10 ==9 || num ==n) {
num/=10;
}
num++;
list.add(num);
}
}
return list;
}
440:字典序的第K小數字(困難)
給定整數 n 和 k,找到 1 到 n 中字典序第 k 小的數字。
注意:1 ≤ k ≤ n ≤ 109。
示例 :
輸入:
n: 13 k: 2
輸出:
10
解釋:
字典序的排列是 [1, 10, 11, 12, 13, 2, 3, 4, 5, 6, 7, 8, 9],所以第二小的數字是 10。
來源:力扣(LeetCode)
思路
由於做了386題,再來做這題,就會上來暴露求解,代碼如下,時間會超時。因爲那樣,你是要把沒個數給求出來。而這裏,我們只需要把子節點得個數確定好,就可以了。
public int findKthNumber(int n, int k) {
if(k==1) return 1;
List<Integer> list = new ArrayList<>();
int num = 1;
int count =1;
list.add(1);
for(int i = 1;i<n;i++) {
if(num*10 <=n) {
num*=10;
list.add(num);
count++;
}
else {
while(num%10 ==9 || num ==n) {
num/=10;
}
num++;
list.add(num);
count++;
}
if(count == k)
break;
}
return list.get(k-1);
}
按給出得實例,作爲分析例子:
[1, 10, 11, 12, 13, 2, 3, 4, 5, 6, 7, 8, 9]
標註部分爲同一層兩個相鄰的節點的子節點的個數。
1:當前節點爲 cur(從cur = 1 開始),則同一層的下一個節點爲 curr+1;
2:計算節點 curr到節點curr+1之間的子節點個數step
3:如果子節點個數 大於 k,說明第k小的樹一定在子節點中,那麼繼續向下一層尋找:cur *=10; k -= 1;
(原因:向下一層尋找,肯定要減少前面的父節點,即 在上一層中的第k個數,在下一層中是第k-1個數)
4:如果子節點個數 小於或者等於 k,說明第k小的樹不在子節點中,繼續向同一層下一個節點尋找:curr +=1; k -= steps;
(原因:向下一層尋找,肯定要減少前面的所有的字節點)
以此類推,直到k爲0推出循環,此時cur即爲所求。
代碼實現
public int findKthNumber(int n, int k) {
int cur =1;
k =k-1;
while(k>0){
long step =0;
long first = cur;
long last = cur+1;
while(first<=n){
step+=Math.min((long)n+1,last)-first;
first*=10;
last*=10;
}
if(step<=k){
cur+=1;
k-=step;
}
else{
cur*=10;
k=k-1;
}
}
return cur;
}
注意:定義得step,first,last 定義爲Long,不然會溢出,導致錯誤