描述

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

算法分析

难度:中

分析:这里需要跟大家介绍一下相关的几个概念:

排列(Arrangement),简单讲是从N个不同元素中取出M个,按照一定顺序排成一列,通常用A(M,N)表示。当M=N时,称为全排列(Permutation)

例如对于一个集合A={1,2,3},首先获取全排列a1: 1,2,3;然后获取下一个排列a2: 1,3,2;

按此顺序,A的全排列如下,共6种:

a1: 1,2,3;  a2: 1,3,2;  a3: 2,1,3;  a4: 2,3,1;  a5: 3,1,2;  a6: 3,2,1;  

从数学角度讲,全排列的个数A(N,N)=(N)*(N-1)*...*2*1=N!,但从编程角度,如何获取所有排列?那么就必须按照某种顺序逐个获得下一个排列,通常按照升序顺序(字典序lexicographically)获得下一个排列。

对于给定的任意一种全排列,如果能求出下一个全排列的情况,那么求得所有全排列情况就容易了,也就是题目要求实现的下一个全排列算法(Next Permutation)

思路

设目前有一个集合的一种全排列情况A : 1,5,8,4,7,6,5,3,1,求取下一个排列的步骤如下:

/** Tips: next permuation based on the ascending order sort
* sketch :
* current: 1 5 8 4 7 6 5 3 1
* | | |
* find i----+ j +----end
* swap i and j :
* 1 5 8 5 7 6 4 3 1
* | | |
* j----+ i +----end
* reverse j+1 to end :
* 1 5 8 5 1 3 4 6 7
* | |
* find j----+ +----end
* */

具体方法为:

a)从后向前查找第一个相邻元素对(i,i+1),并且满足A[i] < A[i+1]。

易知,此时从j到end必然是降序。可以用反证法证明,请自行证明。

b)在[i+1,end)中寻找一个最小的j使其满足A[i]<A[j]。

由于[j,end)是降序的,所以必然存在一个j满足上面条件;并且可以从后向前查找第一个满足A[i]<A[j]关系的j,此时的j必是待找的j。

c)将i与j交换。

此时,i处变成比i大的最小元素,因为下一个全排列必须是与当前排列按照升序排序相邻的排列,故选择最小的元素替代i。

易知,交换后的[j,end)仍然满足降序排序。

d)逆置[j,end)

由于此时[j,end)是降序的,故将其逆置。最终获得下一全排序。

注意:如果在步骤a)找不到符合的相邻元素对,即此时i=begin,则说明当前[begin,end)为一个降序顺序,即无下一个全排列,于是将其逆置成升序。

代码示例(C#)

public void NextPermutation(int[] nums)
{
int i = nums.Length - 2;
//末尾向前查找,找到第一个i,使得A[i] < A[i+1]
while (i >= 0 && nums[i + 1] <= nums[i])
{
i--;
}
if (i >= 0)
{
//从i下标向后找第一个j,使得A[i]<A[j]
int j = nums.Length - 1;
while (j >= 0 && nums[j] <= nums[i])
{
j--;
}
//交换i,j
Swap(nums, i, j);
}
//逆置j之后的元素
Reverse(nums, i + 1, nums.Length);
} //逆置排序
private void Reverse(int[] nums, int start, int end)
{
int i = start, j = end - 1;
while (i < j)
{
Swap(nums, i, j);
i++;
j--;
}
} //交换
private void Swap(int[] nums, int i, int j)
{
int temp = nums[i];
nums[i] = nums[j];
nums[j] = temp;
}

复杂度

  • 时间复杂度O (n).
  • 空间复杂度O (1).

附录

算法题丨Next Permutation的更多相关文章

  1. LeetCode算法题-Letter Case Permutation(Java实现)

    这是悦乐书的第315次更新,第336篇原创 01 看题和准备 今天介绍的是LeetCode算法题中Easy级别的第184题(顺位题号是784).给定一个字符串S,将每个字母单独转换为小写或大写以创建另 ...

  2. 算法题丨Remove Duplicates from Sorted Array II

    描述 Follow up for "Remove Duplicates": What if duplicates are allowed at most twice? 示例 Giv ...

  3. 算法题丨Longest Consecutive Sequence

    描述 Given an unsorted array of integers, find the length of the longest consecutive elements sequence ...

  4. 算法题丨Two Sum

    描述 Given an array of integers, return indices of the two numbers such that they add up to a specific ...

  5. 算法题丨3Sum

    描述 Given an array S of n integers, are there elements a, b, c in S such that a + b + c = 0? Find all ...

  6. 算法题丨3Sum Closest

    描述 Given an array S of n integers, find three integers in S such that the sum is closest to a given ...

  7. 算法题丨4Sum

    描述 Given an array S of n integers, are there elements a, b, c, and d in S such that a + b + c + d = ...

  8. 算法题丨Remove Element

    描述 Given an array and a value, remove all instances of that value in-place and return the new length ...

  9. 算法题丨Move Zeroes

    描述 Given an array nums, write a function to move all 0's to the end of it while maintaining the rela ...

随机推荐

  1. nodejs利用superagent爬取数据的简单例子

    爬取世界银行统计数据 安装:npm install superagent /** * Created by zh on 16-9-7. */ var request = require('supera ...

  2. Konckout第四个实例:组合类型数据绑定 -- 日期双向绑定显示

    <!doctype html> <html > <head> <meta http-equiv="Content-Type" conten ...

  3. sql操作知识点个人笔记(SQLServer篇)

    实际工作中,总会遇到一些常用的或不常用的sql,这些sql可能并没多少技术含量,但对我们本身而言,一个最大的问题就是很容易忘记.对我个人而言,以前常用的,过阵子之后再用到,发现不记得了.由此得出结论, ...

  4. Win7(64Bit旗舰版) 安装 PL/SQL Developer图解说明

    Win7逐渐成为现行主流的windows操作系统,其32和64位系统平分秋色.然而当下还没有64位的PL/SQL Developer问世,直接用32位的PL/SQL Developer连接Win7(6 ...

  5. C语言博客作业-结构体

    一.PTA实验作业 6-2 按等级统计学生成绩 1. 本题PTA提交列表 2. 设计思路 定义i,count存放不及格人数 for i=0 to n-1{ 判断 score的值的范围 if 100&g ...

  6. 201621123068 Week03-面向对象入门

    1. 本周学习总结 初学面向对象,会学习到很多碎片化的概念与知识.尝试学会使用思维导图将这些碎片化的概念.知识点组织起来.请使用工具画出本周学习到的知识点及知识点之间的联系.步骤如下: 1.1 写出你 ...

  7. 库函数atoi

    函数名:atoi 功能: 把一个字符串转换成一个整数. 看似简单,主要是情况太多,需要注意考虑. 测试代码: Test(NULL); Test(""); Test("12 ...

  8. ExecutorService实际上是一个线程池的管理工具

    在Java5之后,并发线程这块发生了根本的变化,最重要的莫过于新的启动.调度.管理线程的一大堆API了.在Java5以后,通过Executor来启动线程比用 Thread的start()更好.在新特征 ...

  9. 20145237 实验五《Java网络编程》

    20145237 实验五<Java网络编程> 一.实验内容 •1.运行下载的TCP代码,结对进行,一人服务器,一人客户端: •2.利用加解密代码包,编译运行代码,一人加密,一人解密: •3 ...

  10. 第一周-JAVA基本概念

    1. 本周学习总结 本周学习内容: 1.JAVA的发展 2.JDK,JVM,JRE, 3.掌握JAVA的组成结构 4.掌握使用简单的编译器写javac与java命令, 关键概念之间的联系: JVM:将 ...