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 and use only constant 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
找到从前往后最大序号的一个元素(假设序号为j),从后往前找值和序号均比它大的元素(假设序号为i),将这两个元素交换后,还要将序号为j之后的所有元素升序排序。
这样找得到的序列是下一个更大的字典序排序是因为i是从前往后找其后还有比它自身值更大的元素的最大序号,这样当从后往前找时在i之后不会再存在一个元素,其后还有元素比它自身的值更大。这样的结果就是nums[j]已经是i之后所有元素中最小的比nums[i]大的元素了。简而言之,就是找到一个元素,在该元素之后还有元素比它值更大,且该元素已经是满足前面条件的最大序号元素,然后将该元素与其后比它大的元素中值最小的元素互换位置,最后将交换之后序号在i之后的所有元素按升序排序即可。
class Solution {
public:
//找到从前往后最大序号的一个元素(假设序号为j),从后往前找值和序号均比它大的元素(假设序号为i),将这两个元素交换后,还要将序号为j之后的所有元素升序排序
//这样获得的才是next greater permutation of numbers.
void nextPermutation(vector& nums) {
int len = nums.size();
if (len <= 1)
return;
bool isgreatest = true;
int record_left = 0, record_right = 0; //record_left,record_right要是能换的最大序号,
for (int i = len - 1; i > 0; --i) {
for (int j = i - 1; j >= 0; --j) {
if (nums[j] < nums[i]) {
if (j > record_left || (j == record_left && i >= record_right)) {
record_left = j;
record_right = i;
isgreatest = false;
}
}
}
}
if (isgreatest) {
//如果已经是最大字典序了,则返回最小字典序
reverse(nums);
}
else {
swap(nums[record_left], nums[record_right]);
sort(nums, record_left+1);
}
}
void swap(int &a, int&b) {
int temp = a;
a = b;
b = temp;
}
void sort(vector &nums, int begin) {
if (begin >= nums.size() - 1)
return;
int tmp = 0;
int lastExchangeIndex = 0;//记录最后一次交换的位置
int sortBorder = nums.size() - 1;//无序数组的边界,每次比较只需要比较到这里为止
for (int i = begin; i < nums.size(); ++i) {
//有序标记,每一轮的初始是true
bool issorted = true;
for (int j = begin; j < sortBorder; ++j) {
if (nums[j] > nums[j + 1]) {
//有元素交换,所以不是有序,标记为false
issorted = false;
swap(nums[j], nums[j + 1]);
//把无序数列的边界更新为最后一次交换元素的位置
lastExchangeIndex = j;
}
}
sortBorder = lastExchangeIndex;
if (issorted)
break; //如果已经是有序的了,直接结束循环,不需要继续后面的比较了
}
}
void reverse(vector &nums) {
int left = 0, right = nums.size() - 1;
while (left <= right) {
swap(nums[left], nums[right]);
++left;
--right;
}
}
};
Complexity Analysis
Time complexity : O(n). In worst case, only two scans of the whole array are needed.
Space complexity : O(1). No extra space is used. In place replacements are done.
JAVA代码实现如下:
public class Solution {
public void nextPermutation(int[] nums) {
int i = nums.length - 2;
while (i >= 0 && nums[i + 1] <= nums[i]) {
i--;
}
if (i >= 0) {
int j = nums.length - 1;
while (j >= 0 && nums[j] <= nums[i]) {
j--;
}
swap(nums, i, j);
}
reverse(nums, i + 1);
}
private void reverse(int[] nums, int start) {
int i = start, j = nums.length - 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;
}
}
C++代码如下:
class Solution {
public:
void nextPermutation(vector& nums) {
int n = nums.size(), k, l;
for (k = n - 2; k >= 0; k--) {
if (nums[k] < nums[k + 1]) {
break;
}
}
if (k < 0) {
reverse(nums.begin(), nums.end());
} else {
for (l = n - 1; l > k; l--) {
if (nums[l] > nums[k]) {
break;
}
}
swap(nums[k], nums[l]);
reverse(nums.begin() + k + 1, nums.end());
}
}
};
Solution 1
Just for info: There's a library function that does the job, even going from totally reverse sorted to sorted:
void nextPermutation(vector& nums) {
next_permutation(begin(nums), end(nums));
}
Solution 2
Using library functions for all building blocks of the algorithm. Very nice how they all play together, notice the total lack of +1
/-1
, it all fits exactly.
void nextPermutation(vector& nums) {
auto i = is_sorted_until(nums.rbegin(), nums.rend());
if (i != nums.rend())
swap(*i, *upper_bound(nums.rbegin(), i, *i));
reverse(nums.rbegin(), i);
}
Solution 3
Doing it all on my own (except swap
, let's not be silly):
void nextPermutation(vector& nums) {
int i = nums.size() - 1, k = i;
while (i > 0 && nums[i-1] >= nums[i])
i--;
for (int j=i; j 0) {
k = i--;
while (nums[k] <= nums[i])
k++;
swap(nums[i], nums[k]);
}
}
Solution 4
Ok, let's be silly after all and not even use swap
:-)
void nextPermutation(vector& nums) {
int i = nums.size() - 1, k = i, tmp;
while (i > 0 && nums[i-1] >= nums[i])
i--;
for (int j=i; j 0) {
k = i--;
while (nums[k] <= nums[i])
k++;
tmp = nums[i], nums[i] = nums[k], nums[k] = tmp;
}
}