刷题总结--字典序

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,不然会溢出,导致错误

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