[LeetCode]problem 60. Permutation Sequence
来源:互联网 发布:linux内核开发赚钱吗 编辑:程序博客网 时间:2024/06/04 01:28
TAG
类·进制转换
数学;枚举;找规律
题目链接
方法
首先,第一眼看过去,没看出来规律。
看第二眼,找到了规律: 第高位往低位看,整个随机序列的最高位从1到n的,看某一确定高位下的序列,会发现次高位也是由低到高,只不过不断跳过之前位上已经出现过的单词。从递归的角度来说,这个n位排序随机序列的产生过程如下:
NUM_SEQ = {}NUM_LEN = kdef GENERATE(num_prefix): for i = 1 -> n : if i in num_prefix : continue new_num_prefix = num_prefix + [ i ] if len(new_num_prefix) == NUM_LEN : NUM_SEQ.append(new_num_prefix) continue else : GENERATE(new_num_prefix)
(万万没想到写伪代码竟然写成了Python…)
OK,上面顺序生成序列的过程就算是弄明白了。但是题目是找第k的随机数,可不是要求全部的数。当然不能用枚举的方法来做了,绝对会TLE的吧(9!的也太大了)。
所以我们的问题就变成了,已经知道了上面的生成规则,可不可以直接有第k个数来反推出各位的值呢?
画了一个4!的式子: 4! = 4 x 3 x 2 x 1
, 突然有了想法——将k不断除以和取模1,2,3,4,得到的值是否就是各位上的值(这里的值是相对1的偏移值,还得除去前面已经出现过的数)呢?
随机算了个简单的,恰恰如此!
(列一下吧…)
比如第7个数,首先要把7减去1(作为从0开始计数——为什么会这样,因为第一个数各位必然是0啊,如果不减肯定就不对了)。
那么就是说val = 6
6 / 1 = 6 , 6 % 1 = 0 -> 第1位是0 (偏移0)
6 / 2 = 3 , 6 % 2 = 0 -> 第2为是0
3 / 3 = 1 , 3 % 3 = 0 -> 第3为是0
1 / 4 = 0 , 1 % 4 = 1 -> 第4位是1
ok,最后val的值为0了,就停止。
然后倒过去看(因为是先生成高位),4位数
第4位是1,表示相对于1偏移1,那么就是2
第3位是0,表示相对于1的偏移是0,此时1也没有出现,故就是1
第2位是0,表示相对于1的偏移是0,但此时1、2都出现了,故只能选3
第1位是0,表示相对于1的偏移是0,这是只剩下4
故4位数的随机序列中,第7个就是 2134 .
其实最低位(上述‘第1位’)偏移肯定都是0(从直觉上理解,因为最后一位只有一种选择,从上面的算式理解,正整数模1都是0),所以可以跳过计算,当然不跳过也没什么影响。
上面在想的过程中,其实越来越清晰了——
这不就是类似于十进制转二进制的思想吗!!
然后我们再类别一下,这的确可以认为是一个进制转换问题。n位排列数,其每位的权从高往低,就是(n-1)!,(n-2)!,…,1 (更直观的说,每位的可选数值个数分别是n,n-1,n-2,…,1).类比一下2进制,每位权值就是 2^(n-1),2^(n-2), …, 2^0 (每位的可选数值只有两个). 所以,相对于二进制,这是一个动态进制的数!此外,比二进制转换多一步就是,后面的数与前面是不重复的,所以还有一个选择数字的过程。
转换为进制转换的问题,上述的计算方式就更加可以理解了。这个问题也变得更加有清晰。
代码
class Solution {public: string getPermutation(int n, int k) { assert(k > 0); string result(n,'1'); vector<int> offsets(n,0); vector<bool> hasAppeared(n,false); calcOffset(n, k, offsets); // generate k-th number for(int bitPos = n-1 ; bitPos >= 0 ; --bitPos) { for(int candidateVal = 1 ; candidateVal <= n; ++candidateVal) { if(hasAppeared[candidateVal-1]){ continue ;} if( 0 == offsets[bitPos] ) { result[n-1-bitPos] = candidateVal - 1 + '1' ; hasAppeared[candidateVal-1] = true; break; } else{ --offsets[bitPos]; } } } return result; }private: void calcOffset(int bitNum, int order, vector<int> &offsets) { --order ; // let it count from 0 instead of 1 size_t bitPos = 0 ; while(bitPos < bitNum && order != 0) // in fact , if order is valid , there is no need for condition `bitPos < bitNum` { int curPosWeight = bitPos + 1; offsets[bitPos] = order % curPosWeight ; order /= curPosWeight; ++bitPos; } }};
- [LeetCode]problem 60. Permutation Sequence
- LeetCode --- 60. Permutation Sequence
- [Leetcode] 60. Permutation Sequence
- [leetcode] 60.Permutation Sequence
- **LeetCode 60. Permutation Sequence
- leetcode 60. Permutation Sequence
- [LeetCode]60. Permutation Sequence
- LeetCode *** 60. Permutation Sequence
- LeetCode 60. Permutation Sequence
- leetcode 60. Permutation Sequence
- LeetCode 60. Permutation Sequence
- leetcode:60. Permutation Sequence
- [Leetcode] 60. Permutation Sequence
- [leetcode] 60. Permutation Sequence
- [LeetCode] 60. Permutation Sequence
- leetcode 60. Permutation Sequence
- Leetcode-60. Permutation Sequence
- [LeetCode]--60. Permutation Sequence
- 哈希散列
- AR(增强现实) unity+vuforia 基础教程(1)!
- drools-spring-1.0.0.xsd所在的drools-spring.jar已
- ListView的使用技巧集合(五)
- 山东省第七届ACM省赛------Reversed Words
- [LeetCode]problem 60. Permutation Sequence
- E
- Exchange 2010 PS 之 Get-MessageTracking命令!
- HOJ 1020
- 【笔记】投影坐标到屏幕坐标
- SICP 习题2.21 square-list
- 文章标题
- 动态维护数列的中位数
- 进程、线程和协程的区别是什么