leetcode字典序题目总结

生成下一个字典序

Implement next permutation, which rearranges numbers into the lexicographically next greater permutation of numbers.

If such arrangement is not possible, it must rearrange it as the lowest possible order (ie, sorted in ascending order).

The replacement must be in-place and use only constant extra memory.

Here are some examples. Inputs are in the left-hand column and its corresponding outputs are in the right-hand column.

1,2,3 → 1,3,2
3,2,1 → 1,2,3
1,1,5 → 1,5,1

思路:

class Solution {
public:
    void nextPermutation(vector<int>& nums) {
        int n = nums.size(),i,j;
        if(n < 2) return;
        
        for(i = n-2;i >= 0;i--){
            // 找到第一个逆序位置
            if(nums[i] < nums[i+1]){
                // 找最靠近nums[i]且比它大的数
                j = n-1;
                for(;j > i;j--){
                    if(nums[j] > nums[i]) break;
                }
                // 交换
                swap(nums[i],nums[j]);
                // i后面按照顺序排列
                reverse(nums.begin()+i+1,nums.end());
                return;
            }
        }
        // 完全从后往前顺序的情况
        sort(nums.begin(),nums.end());
    }
};

 

生成1-n的字典序数字 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.

以780为例

1,10,100,101...109,11,110,111...119,12,120,121..129...199

class Solution {
public:
    vector<int> lexicalOrder(int n) {
        vector<int> res(n);
        int cur = 1;
        // 顺序生成
        for(int i = 0;i < n;i++){
            res[i] = cur;
            if(cur*10 <= n) cur *= 10;
            else{
                if(cur >= n) cur /= 10;
                cur += 1;
                while (cur % 10 == 0) cur /= 10;
            }
        }
        return res;
    }
};

 

 

字典序第k个排列

The set [1,2,3,...,n] contains a total of n! unique permutations.

By listing and labeling all of the permutations in order, we get the following sequence for n = 3:

  1. "123"
  2. "132"
  3. "213"
  4. "231"
  5. "312"
  6. "321"

Given n and k, return the kth permutation sequence.

Note:

  • Given n will be between 1 and 9 inclusive.
  • Given k will be between 1 and n! inclusive.

思路:https://www.cnblogs.com/grandyang/p/4358678.html

class Solution {
public:
    string getPermutation(int n, int k) {
        string res;
        string nums = "123456789";
        vector<int> f(n,1);
        for(int i = 1;i < n;i++){
            f[i] = f[i-1]*i;
        }
        // 从第0个开始排
        --k;
        for(int i = n;i > 0;i--){
            // 每次都去除剩下可能的排列数,来确定当前应该是什么数
            int j = k/f[i-1];
            k = k%f[i-1];
            res += nums[j];
            // 注意这里的删去,使得每次挑选是从未被排列过的数中挑选
            nums.erase(j,1);
        }
        return res;
    }
};

 

找字典序的第k个数 K-th Smallest in Lexicographical Order

Given integers n and k, find the lexicographically k-th smallest integer in the range from 1 to n.

Note: 1 ≤ k ≤ n ≤ 109.

Example:

Input:
n: 13   k: 2

Output:
10

Explanation:
The lexicographical order is [1, 10, 11, 12, 13, 2, 3, 4, 5, 6, 7, 8, 9], so the second smallest number is 10.

其实这是个十叉树Denary Tree,就是每个节点的子节点可以有十个,比如数字1的子节点就是10到19,数字10的子节点可以是100到109,但是由于n大小的限制,构成的并不是一个满十叉树。

我们分析题目中给的例子可以知道,数字1的子节点有4个(10,11,12,13),而后面的数字2到9都没有子节点,那么这道题实际上就变成了一个先序遍历十叉树的问题,那么难点就变成了如何计算出每个节点的子节点的个数,我们不停的用k减去子节点的个数,当k减到0的时候,当前位置的数字即为所求。

现在我们来看如何求子节点个数,比如数字1和数字2,我们要求按字典遍历顺序从1到2需要经过多少个数字,首先把1本身这一个数字加到step中,然后我们把范围扩大十倍,范围变成10到20之前,但是由于我们要考虑n的大小,由于n为13,所以只有4个子节点,这样我们就知道从数字1遍历到数字2需要经过5个数字,然后我们看step是否小于等于k,如果是,我们cur自增1,k减去step;如果不是,说明要求的数字在子节点中,我们此时cur乘以10,k自减1,以此类推,直到k为0推出循环,此时cur即为所求

class Solution {
public:
    int findKthNumber(int n, int k) {
        int cur = 1;
        --k;
        while(k > 0){
            long long step = 0,first = cur,last = cur+1;
            // 遍历1开头树,2开头树。。。
            while(fisrt < n){
                step += min((long long)n+1,last)-first;
                first *= 10;
                last *= 10;
            }
            // 1开头树数量小于k
            if(step <= k){
                ++cur;
                k -= step;
            } 
            // 否则,在树内,找10开头的数
            else{
                cur *= 10;
                --k;
            }
        }
    }
};
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值