[LeetCode] “全排列”问题系列(二) - 基于全排列本身的问题,例题: Next Permutation , Permutation Sequence
一、开篇
既上一篇<交换法生成全排列及其应用> 后,这里讲的是基于全排列 (Permutation)本身的一些问题,包括:求下一个全排列(Next Permutation);求指定位置的全排列(Permutation Sequence);给出一个全排列,求其所在位置。
二、例题
1. 求下一个全排列,Next permuation
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, do not allocate 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> &num) {
}
};
题目的意思是假设所有的全排列按照字典顺序被排列,找给定全排列的下一个。
我的思路是:所谓下一个全排列,其实就是将当前vetor的一个子集重排而已。这个子集如何划分?
考虑排列1237456,它的下一个排列是1243567,找子集的方法其实就是:从头到尾找到最后一个满足 num[i+1] > num[i] 的一对(实现时可以从尾到头遍历,找到第一个num[i+1] > num[i] 的一对),需要重排的子集就是 num[i~size-1] 这个子集。这个子集num[i~size-1] 满足一个条件:前两个元素递增,后面都是递减或者后面已经没有元素。特殊情况是:如果找不到这样的存在递增关系的 num[i] 和 num[i+1],说明整个序列都是降序,也就是没有更大的排列了,根据题目要求,直接将序列逆序即可。
重新排列的方式就是从num[i+1 ~ size-1]中选一个比num[i] 大的最小元素,将其和num[i] 交换,然后将num[+1 ~ size-1]逆序。
代码:
class Solution {
public:
void nextPermutation(vector<int> &num) {
int size = num.size();
if(size == || size == ) return;
int ascHead = size - ; //最后一个num[i] < num[i+1] 的 i
for(; ascHead >= && num[ascHead] >= num[ascHead + ]; --ascHead);
if(ascHead < ){reverse(num, , size-); return;}
int insert = size - ; //存储那个比num[ascHead]大的最小值的index
for(; insert > ascHead && num[insert] <= num[ascHead]; --insert);
swap(num, ascHead, insert);
reverse(num, ascHead+, size-);
}
private:
void swap(vector<int> &num, int left, int right){
int temp = num[left];
num[left] = num[right];
num[right] = temp;
} void reverse(vector<int> &num, int start, int end){
while(start < end){
swap(num, start++, end--);
}
}
};
2. 给一个全排列,求其在所有全排列中位于第几位
这道题上LeetCode上没有例题。
例如给定一个排列 356421, 因为第一位为3,因此1 和 2 开头的全排列已经经过了,以1开头的全排列个数为5!,2也是。因此该全排列的排名 > 2 * 5!
第二位为5,对于以3开头的全排列,排在35前面的有31,32,34开头的三个全排列。在356421中,5右边比5小的也正是1,2,4。
我们可以发现:序列长度为n,对于给定排列P某位上的数,假设这个数在P上从右起排第m位,我们只要看看该数右侧的位数上还有几个比它小的,就知道该数以右的部分在对应所有子序列中的排名了。
因此P的总排名 = ∑k*m! (m从0到n-1,k表示第m+1位之后有多少小于第m+1位个数。
3. 求指定位置的全排列
Permutation Sequence
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 (ie, for n = 3):
"123"
"132"
"213"
"231"
"312"
"321"
Given n and k, return the kth permutation sequence.
Note: Given n will be between 1 and 9 inclusive
class Solution {
public:
string getPermutation(int n, int k) {
}
};
有了上一题的思路,这一題就很容易了。
无非就是不断除以m!,m在递减,将余数作为分母继续循环。
class Solution {
public:
string getPermutation(int n, int k) {
bool dig[n];
unsigned int mul = ;
int j = , ind = , i = ;
string res = "";
for(i = ; i < n; mul *= (i>?i:), dig[i] = false, ++i);
--k; //将k偏移,将0作为第一位
for(i = n; i > ; --i, k %= mul, mul /= (i>?i:)){
ind = k/mul;
for(j = ; j < n; ++j){
if(!dig[j]) --ind;
if(ind < ) break;
}
dig[j] = true;
res.push_back(j + ''); //这里j从0开始算,因此转化成字符要+'1'
} return res;
}
};
三、总结:
基于全排列本身可以出不少题目,但是我们只要知道全排列的数量是按照 k! 计算的,就可以从这里入手。
如果想构造全排列,上一文中的交换法就是一个思路
[LeetCode] “全排列”问题系列(二) - 基于全排列本身的问题,例题: Next Permutation , Permutation Sequence的更多相关文章
- Keil MDK STM32系列(二) 基于标准外设库SPL的STM32F401开发
Keil MDK STM32系列 Keil MDK STM32系列(一) 基于标准外设库SPL的STM32F103开发 Keil MDK STM32系列(二) 基于标准外设库SPL的STM32F401 ...
- Keil MDK STM32系列(九) 基于HAL和FatFs的FAT格式SD卡TF卡读写
Keil MDK STM32系列 Keil MDK STM32系列(一) 基于标准外设库SPL的STM32F103开发 Keil MDK STM32系列(二) 基于标准外设库SPL的STM32F401 ...
- Keil MDK STM32系列(一) 基于标准外设库SPL的STM32F103开发
Keil MDK STM32系列 Keil MDK STM32系列(一) 基于标准外设库SPL的STM32F103开发 Keil MDK STM32系列(二) 基于标准外设库SPL的STM32F401 ...
- Keil MDK STM32系列(三) 基于标准外设库SPL的STM32F407开发
Keil MDK STM32系列 Keil MDK STM32系列(一) 基于标准外设库SPL的STM32F103开发 Keil MDK STM32系列(二) 基于标准外设库SPL的STM32F401 ...
- Keil MDK STM32系列(四) 基于抽象外设库HAL的STM32F401开发
Keil MDK STM32系列 Keil MDK STM32系列(一) 基于标准外设库SPL的STM32F103开发 Keil MDK STM32系列(二) 基于标准外设库SPL的STM32F401 ...
- Keil MDK STM32系列(六) 基于抽象外设库HAL的ADC模数转换
Keil MDK STM32系列 Keil MDK STM32系列(一) 基于标准外设库SPL的STM32F103开发 Keil MDK STM32系列(二) 基于标准外设库SPL的STM32F401 ...
- Leetcode之回溯法专题-47. 全排列 II(Permutations II)
Leetcode之回溯法专题-47. 全排列 II(Permutations II) 给定一个可包含重复数字的序列,返回所有不重复的全排列. 示例: 输入: [1,1,2] 输出: [ [1,1,2] ...
- CRL快速开发框架系列教程二(基于Lambda表达式查询)
本系列目录 CRL快速开发框架系列教程一(Code First数据表不需再关心) CRL快速开发框架系列教程二(基于Lambda表达式查询) CRL快速开发框架系列教程三(更新数据) CRL快速开发框 ...
- Leetcode之回溯法专题-46. 全排列(Permutations)
Leetcode之回溯法专题-46. 全排列(Permutations) 给定一个没有重复数字的序列,返回其所有可能的全排列. 示例: 输入: [1,2,3] 输出: [ [1,2,3], [1,3, ...
随机推荐
- 深入理解JavaScript 事件
本文总结自<JavaScript高级程序设计>以及自己平时的经验,针对较新浏览器以及 DOM3 级事件标准(2016年8月),对少部分内容作了更正,增加了各种例子及解析. 如无特殊说明,本 ...
- MATLAB实现将图像转换为素描(简笔画)风格
代码: colorgrad.m function [VG, A, PPG] = colorgrad(f, T) ) || (size(f,)~=) error('Input image must be ...
- atitit.添加win 系统服务 bat批处理程序服务的法总结instsrv srvany java linux
atitit.添加win 系统服务 bat批处理程序服务的法总结instsrv srvany java linux 系统服务不同于普通视窗系统应用程式.不可能简简单单地通过运行一个EXE就启动视窗系 ...
- python web框架——初识tornado
一 Tornado概述 Tornado是FriendFeed使用的可扩展的非阻塞式web框架及其相关工具的开源版本.这个Web框架看起来有些像web.py或者Google的 webapp,不过为了能有 ...
- 从委托、匿名方法到Lambda
前面讲过委托的知识,本次由委托过渡到Lambda表达式,更易于理解. class Program { static void Main(string[] args) { , , , }; ProcAr ...
- [原创]软件质量保证圈QQ群:197915314
[原创]软件质量保证圈QQ群:197915314 软件质量保证圈QQ群:197915314,讨论软件工程.软件过程改进.软件质量保证等(非测试群)! 欢迎各位同学来,来时请自报家门,名片修改格式:sh ...
- 在cxf中使用配置避免增加字段导致客户端必须更新、同步实体属性的问题
在使用cxf实现webservice时,经常碰到的问题就是如果在服务端,修改了一个接口的签名实现,如增加一个字段,或者删除一个字段.在这种情况下,在默认的配置中,就会报以下的错误信息: org.apa ...
- 【迁移】—Entity Framework实例详解
好久没有在博客园更新博客了,如今都换了新公司.前段时间写了关于EF迁移的文档,今天拿出来作为这个系列的一篇吧. 一.Entity Framework 迁移命令(get-help EntityFrame ...
- MySQL实现定时任务
如果要每30秒执行以下语句 '; 可以给MySQL建个定时任务,具体如下: delimiter // /* 设定语句终结符为 //,因存储过程语句用;结束 */ 一.查看event是否开启 show ...
- eclipse快捷键调试总结【转】
http://www.cnblogs.com/yxnchinahlj/archive/2012/02/22/2363542.html (1)Ctrl+M --切换窗口的大小(2)Ctrl+Q --跳到 ...