一、开篇

既上一篇<交换法生成全排列及其应用> 后,这里讲的是基于全排列 (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):

  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

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的更多相关文章

  1. Keil MDK STM32系列(二) 基于标准外设库SPL的STM32F401开发

    Keil MDK STM32系列 Keil MDK STM32系列(一) 基于标准外设库SPL的STM32F103开发 Keil MDK STM32系列(二) 基于标准外设库SPL的STM32F401 ...

  2. Keil MDK STM32系列(九) 基于HAL和FatFs的FAT格式SD卡TF卡读写

    Keil MDK STM32系列 Keil MDK STM32系列(一) 基于标准外设库SPL的STM32F103开发 Keil MDK STM32系列(二) 基于标准外设库SPL的STM32F401 ...

  3. Keil MDK STM32系列(一) 基于标准外设库SPL的STM32F103开发

    Keil MDK STM32系列 Keil MDK STM32系列(一) 基于标准外设库SPL的STM32F103开发 Keil MDK STM32系列(二) 基于标准外设库SPL的STM32F401 ...

  4. Keil MDK STM32系列(三) 基于标准外设库SPL的STM32F407开发

    Keil MDK STM32系列 Keil MDK STM32系列(一) 基于标准外设库SPL的STM32F103开发 Keil MDK STM32系列(二) 基于标准外设库SPL的STM32F401 ...

  5. Keil MDK STM32系列(四) 基于抽象外设库HAL的STM32F401开发

    Keil MDK STM32系列 Keil MDK STM32系列(一) 基于标准外设库SPL的STM32F103开发 Keil MDK STM32系列(二) 基于标准外设库SPL的STM32F401 ...

  6. Keil MDK STM32系列(六) 基于抽象外设库HAL的ADC模数转换

    Keil MDK STM32系列 Keil MDK STM32系列(一) 基于标准外设库SPL的STM32F103开发 Keil MDK STM32系列(二) 基于标准外设库SPL的STM32F401 ...

  7. Leetcode之回溯法专题-47. 全排列 II(Permutations II)

    Leetcode之回溯法专题-47. 全排列 II(Permutations II) 给定一个可包含重复数字的序列,返回所有不重复的全排列. 示例: 输入: [1,1,2] 输出: [ [1,1,2] ...

  8. CRL快速开发框架系列教程二(基于Lambda表达式查询)

    本系列目录 CRL快速开发框架系列教程一(Code First数据表不需再关心) CRL快速开发框架系列教程二(基于Lambda表达式查询) CRL快速开发框架系列教程三(更新数据) CRL快速开发框 ...

  9. Leetcode之回溯法专题-46. 全排列(Permutations)

    Leetcode之回溯法专题-46. 全排列(Permutations) 给定一个没有重复数字的序列,返回其所有可能的全排列. 示例: 输入: [1,2,3] 输出: [ [1,2,3], [1,3, ...

随机推荐

  1. paip.c3p0 nullpointexcept 配置文件根路径读取bug 解决

    paip.c3p0 nullpointexcept 配置文件根路径读取bug 解决 windows ok linux犯错误... 查看loging, 初始化的时候儿jdbcurl,user,pwd都是 ...

  2. 更改Windows系统的密码之后,SQL Server 2008服务无法启动

    问题:更改Windows操作系统的密码之后,SQL Server 2008服务无法启动. 原因:SQL Server服务需要使用操作系统的某个登录账户. 解决:需要在服务的属性窗口中修改账户密码,然后 ...

  3. Android 发布可穿戴设备 SDK 的开发者预览版

    今早上安卓官网查资料,发现网站上赫然显示着"Android Wear"几个大字.难道……?点进去看,果然,Android发布了可穿戴设备的SDK的开发者预览版. 其中这第五张图…… ...

  4. 【干货】个人工作文档节选:XAML MVVM 框架易用性细节优化Tips

    1    易用性细节优化 1.1 代码片段 在ViewModel内,会有大量重复性的在Property set中激发 INotifyPropertyChanged.PropertyChanged 事件 ...

  5. Passwordless SSH Login

    原文地址:http://manjeetdahiya.com/2011/03/03/passwordless-ssh-login/ Consider two machines A and B. We w ...

  6. Oracle User Calls 和 Executions 两个概念的区别

    User calls = (User session Login + Parsing within a session + Executions of sql's/Cursors ) per seco ...

  7. Spark随机深林扩展—OOB错误评估和变量权重

    本文目的 当前spark(1.3版)随机森林实现,没有包括OOB错误评估和变量权重计算.而这两个功能在实际工作中比较常用.OOB错误评估可以代替交叉检验,评估模型整体结果,避免交叉检验带来的计算开销. ...

  8. mysql 关键字 字段 转义

    insert into tb_gps(imei,lat,lon,speed,dir,alt,atom,`signal`,batt,intime) values('46345435435345','22 ...

  9. Oracle中group by用法

    Oracle中group by用法 在select 语句中可以使用group by 子句将行划分成较小的组,一旦使用分组后select操作的对象变为各个分组后的数据,使用聚组函数返回的是每一个组的汇总 ...

  10. python环境中运行程序

    运行Python程序,我们比较常用的是直接在Windows命令提示窗口或者Linux终端或shell窗口中,直接:Python *.py,或者在Linux环境下,在投不中,加入: #!/usr/bin ...