刷題總結--字典序

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,不然會溢出,導致錯誤

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章