描述

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. 网络通信 --> ZMQ安装和使用

    ZMQ安装和使用 ZMQ 并不像是一个传统意义上的消息队列服务器,事实上,它也根本不是一个服务器,它更像是一个底层的网络通讯库,在 Socket API 之上做了一层封装,将网络通讯.进程通讯和线程通 ...

  2. SSH三大框架整合案例

    SSH三大框架的整合   SSH三个框架的知识点 一.Hibernate框架 1. Hibernate的核心配置文件 1.1 数据库信息.连接池配置 1.2 Hibernate信息 1.3 映射配置 ...

  3. JavaOOP-集合框架

    1.Java集合框架包含的内容 Java集合框架为我们提供了一套性能优良,使用方便的接口和类,它们都位于在java.util包中. Collection 接口存储一组不唯一,无序的对象. List 接 ...

  4. 关于hbase中的hbase-site.xml 配置详解

    该文档是用Hbase默认配置文件生成的,文件源是 hbase-default.xml hbase.rootdir 这个目录是region server的共享目录,用来持久化HBase.URL需要是'完 ...

  5. .NET Core初体验 在window上构建第一个app

    ASP.NET Core 是一个跨平台,高性能的开源框架,用于构建现代化的,基于云的互联网应用程序.使用 ASP.NET Core ,您可以: 构建Web应用程序和服务,IoT应用程序和移动后端. 在 ...

  6. Java虚拟机之类加载机制

    ⑴背景   Java虚拟机把Class文件加载到内存中,并对数据进行校验,转换解析,和初始化,最终形成被虚拟机直接使用的Java类型,这就是类加载机制. ⑵Jvm加载Class文件机制原理 类的生命周 ...

  7. python全栈开发-Day12 三元表达式、函数递归、匿名函数、内置函数

    一. 三元表达式 一 .三元表达式 仅应用于: 1.条件成立返回,一个值 2.条件不成立返回 ,一个值 def max2(x,y): #普通函数定义 if x > y: return x els ...

  8. nodejs安装和卸载

    Ubuntu 上安装 Node.js 方式一:直接安装    一.安装 1.$ sudo apt-get install nodejs2.$ sudo apt-get install npm二.升级 ...

  9. Beta冲刺Day7

    项目进展 李明皇 今天解决的进度 部分数据传递和使用逻辑测试 林翔 今天解决的进度 服务器端查看个人发布的action,修改已发布消息状态的action,仍在尝试使用第三方云存储功能保存图片 孙敏铭 ...

  10. datetimepicker.js 使用笔记

    1.官网地址 官网传送门 2.属性及使用示例 2.1调用 html: <input  type="text"  readonly class="date" ...