一、开篇

既上一篇<交换法生成全排列及其应用> 后,这里讲的是基于全排列 (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. atitit.软件开发方法总结O6

    atitit.软件开发方法总结O6 #--cmm/cmmi  都晓得这个. #--IPD集成产品开发 结构化的流程 IPD工具:包括业务及技术上的共工具. 5.考评:包括团队和个人绩效考核两个方面:首 ...

  2. paip 自定义输入法多多输入法词库的备份导出以及导入

    paip 自定义输入法词库的备份导出以及导入 作者Attilax 艾龙,  EMAIL:1466519819@qq.com 来源:attilax的专栏 地址:http://blog.csdn.net/ ...

  3. iOS开发-迭代器模式

    迭代器模式(Iterator),提供一种方法顺序访问一个聚合对象中的各种元素,而又不暴露该对象的内部表示.开发过程中,我们可能需要针对不同的需求,可能需要以不同的方式来遍历整个整合对象,但是我们不希望 ...

  4. IOS设计模式浅析之简单工厂模式(SimpleFactory)

    概述 首先说明一下,简单工厂模式不属于23种GOF设计模式之一.它也称作静态工厂方法模式,是工厂方法模式的特殊实现.这里对简单工厂模式进行介绍,是为本系列后面的工厂方法和抽象工厂模式做一个引子. 定义 ...

  5. ASP.NET MVC4+EasyUI+EntityFrameWork5权限管理系统——菜单模块的实现(二)

    ASP.NET MVC4+EasyUI+EntityFrameWork5权限管理系统——数据库的设计(一) 菜单和模块是在同一个表中,采用的是树形结构,模块菜单表结构如下代码: USE [Permis ...

  6. android: SharedPreferences实现记住密码功能

    既然是实现记住密码的功能,那么我们就不需要从头去写了,因为在上一章中的最佳实 践部分已经编写过一个登录界面了,有可以重用的代码为什么不用呢?那就首先打开 BroadcastBestPractice 项 ...

  7. 如何获得WPA握手包&EWSA破解WPA密码教程[zz]

    获得WPA\WPA2 握手包的方法有很多,下面介绍通过aircrack-ng工具包来载获握手数据包. 1.下载aircrack-ng工具包. 2.终端里输入 sudo airmon-ng start ...

  8. Chrome谷歌浏览器首页被改为Hao123导航怎么办|附各类解决方法【转】

    软件小子:昨天偶然间发现自己的chrome浏览器的首页被篡改成hao123导航了,要是自己设置的还无所谓,但是后面还有尾巴.顿时就火了,又是哪款软件这么流氓,太无良了,我非常确定我肯定是没有勾选什么设 ...

  9. netfilter分析

    转自:http://blog.sina.com.cn/s/blog_a31ff26901013n07.html 一.概述 1. Netfilter/IPTables框架简介 Netfilter/IPT ...

  10. jackson readTree

    String jsonstr = "{\"msg\":{\"head\":{\"version\":\"1.0\&quo ...