leetcode雕虫小技之60. Permutation Sequence

题干: https://leetcode.com/problems/permutation-sequence/

 

要求1~n(1<=n<=9)的数字的全排列序列,中的第k个字符串。

毕竟不是Hard模式,思路还是比较快粗来的,我的思路还是逐层降级法,就是先先确定第一个数字选啥,再确定第二个数字选啥,逐层推下去,直到所有位都选定。产生这个思路的原因是,理论上这题的 暴力解法是把全排列(并排好序)都算出来,然后在取第k个串,这样做的坏处是浪费了很多工作量,因为我既然只要找第k个为何要把所有的排列都找出来呢?明显浪费工作量吧。于是乎那么接下来 的思路就是用一些取巧的方法,直接排除掉一些排列即可,这样就不用一个个数了。那么怎么取巧呢?

如果把这种排列看成一个树形选择结构的话,就会知道,以任意数字开头的字符串个数都是一样的,例如1,2,3三个数以1开头的有2个,以2开头的也有两个,以3开头的同样是两个,用更一般地说法,以x开头的n个元素的排列数为(n-1)!个,既然如此,在上面的例子中,如果我要求第4个元素,显然就不需要到从1开头的串中去找了,直接到2开头的串中去找即可,这样就直接跳过了1开头的所有串。如果有更多元素,那么原理也是一样的,从左到右每选一个位数,就相当于一个确定分组的过程,最终会收敛到唯一的一个值。

代码如下:

package com.example.demo.leetcode;

import java.util.ArrayList;
import java.util.List;

public class PermutationSequence {
    int accumulated = 0;

    static class PickCondition{
        int n;
        int k;
        List<Integer> selected;

        public PickCondition(int n, int k, List<Integer> s){
            this.n = n;
            this.k = k;
            this.selected = s;
        }
    }

    public String getPermutation(int n, int k) {
        accumulated = 0;
        List<Integer> selected = new ArrayList<>();
        while(selected.size()<n){
            pickOne(new PickCondition(n,k,selected));
        }
        StringBuilder sb = new StringBuilder();
        for(Integer it: selected){
            sb.append(it.toString());
        }

        return sb.toString();
    }

    int nextChoice(int choice, int n, List<Integer> selected){
        int p = choice+1;
        while(p<=n && selected.contains(p)){
            p++;
        }
        if(p>n){
            //代表没有下一个可选的了
            return -1;
        }else{
            return p;
        }
    }

    /**
     * tested
     * @param num
     * @return
     */
    int perm(int num){
        int ret = 1;
        int p = num;
        while(p>=1){
            ret=ret*p;
            p--;
        }

        return ret;
    }

    public void pickOne(PickCondition pk){

        //设置为第一个可用选项
        int choice = 0;

        int numLeft = pk.n-pk.selected.size();
        int tempAccumulated = accumulated;
        int preAcc = tempAccumulated;
        int groupCnt = perm(numLeft-1);

        while(tempAccumulated<pk.k){
            preAcc = tempAccumulated;
            tempAccumulated+=groupCnt;
            choice = nextChoice(choice, pk.n, pk.selected);
        }

        accumulated = preAcc;
        pk.selected.add(choice);
    }

    public static void main(String[] args) {
        PermutationSequence demo = new PermutationSequence();
        String ret = demo.getPermutation(4,3);
        System.out.println(ret);
    }

}

 

 

反思:本次代码一次过OJ,感觉很爽。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值