注:此博客不再更新,所有最新文章将发表在个人独立博客limengting.site。分享技术,记录生活,欢迎大家关注
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
解析:字典序
什么字典序,又不是字母……排列?什么鬼……
后来才发现原来是数学中的排列组合,比如“1,2,3”的全排列,依次是:
1 2 3
1 3 2
2 1 3
2 3 1
3 1 2
3 2 1
那么1234的全排列从小到大的顺序也就是字典序的顺序,依次如下:
1234,1243,1324,1342,1423,1432,
2134,2143,2314,2341,2413,2431,
3124,3142,3214,3241,3412,3421,
4123,4132,4213,4231,4312,4321
所以题目的意思是,从上面的某一行重排到期下一行,如果已经是最后一行了,则重排成第一行。
但是也不能根据给出的数组中的数字列出所有排列,因为要求不能占用额外的空间。
例子: 6 5 4 8 7 5 1
一开始没看对方的后面介绍,就自己在想这个排列的下一个排列是怎样的。
首先肯定从后面开始看,1和5调换了没有用。
7、5和1调换了也没有效果,因此而发现了8、7、5、1是递减的。
如果想要找到下一个排列,找到递增的位置是关键。
因为在这里才可以使其增长得更大。
于是找到了4,显而易见4过了是5而不是8或者7更不是1。
因此就需要找出比4大但在这些大数里面最小的值,并将其两者调换。
那么整个排列就成了:6 5 5 8 7 4 1
然而最后一步将后面的8 7 4 1做一个递增。
最后得到下一个排列: 6 5 5 1 4 7 8
bind1st和bind2nd补充:
bind1st和bind2nd函数用于将一个二元算子(binary functor,bf)转换成一元算子(unary functor,uf)。为了达到这个目的,它们需要两个参数:要转换的bf和一个值(v)。
可能这么解释以后大家还不是很清楚,那么就说点白话吧。我们在做比较的时候所写的表达式像 x > k ,x < k,这里的k是一个参数表示你程序里面的表达式要和k值去比较。上面这两个表达式对应的应该是bind2nd ,简单的理解就是把k作为比较表达式的第二个参数。如果使用bind1st则对应的表达式是 k > x,k < x,也就是把k作为比较表达式的第一个参数。大家可能会注意到这里面没有=的比较,先别着急,后面将会说道如何实现=的比较。先举两个例子看看bind1st和bind2nd的用法。
int a[] = {1, 2, 100, 200};
std::vector< int> arr(a, a + 4);
// 移除所有小于100的元素
arr.erase( std::remove_if( arr.begin(), arr.end(),
std::bind2nd( std::less< int>(), 100)), arr.end());
这里的比较表达式相当于arr.value < 100
如果用bind1st则表达的意思就恰恰相反
// 移除所有大于100的元素
arr.erase( std::remove_if( arr.begin(), arr.end(),
std::bind1st( std::less< int>(), 100)), arr.end());
这里的表达式相当于100 < arr.value
当然为了实现删除大于100的元素你同样可以使用bind2nd
// 移除所有大于100的元素
arr.erase( std::remove_if( arr.begin(), arr.end(),
std::bind2nd( std::greater< int>(), 100)), arr.end());
前面说道=的比较,比如说x <= k怎么实现呢,std又提供了一个好东西not1,我们可以说 !(x > k) 和 x <= k是等价的,那么我们看看下面的表达式:
// 移除所有小于等于100的元素
arr.erase( std::remove_if( arr.begin(), arr.end(),
std::not1(std::bind2nd( std::greater< int>(), 100))), arr.end());
说明:not1是否定返回值是单目的函数,std中还有not2它是否定返回值是双目的函数
例子需要包含头文件:
#include <vector>
#include <algorithm>
#include <functional>
本题代码如下:
class Solution {
public:
void nextPermutation(vector<int>& nums) {
next_per(nums.begin(), nums.end());
}
template<typename BidiIt>
bool next_per(BidiIt first, BidiIt last) {
const auto rfirst = reverse_iterator<BidiIt>(last);
const auto rlast = reverse_iterator<BidiIt>(first);
auto pivot = next(rfirst);
while (pivot != rlast && *pivot >= *prev(pivot))
++pivot;
if(pivot == rlast) {
reverse(rfirst, rlast);
return false;
}
auto change = find_if(rfirst, pivot, bind1st(less<int>(), *pivot));
swap(*change, *pivot);
reverse(rfirst, pivot);
return true;
}
};