每天一道LeetCode-----重新实现next_permutation
来源:互联网 发布:mac安装pip ipython 编辑:程序博客网 时间:2024/06/06 05:42
Next Permutation
原题链接Next Permutation
重新实现next_permulation函数
template <class BidirectionalIterator>bool next_permutation (BidirectionalIterator first, BidirectionalIterator last);
next_permulation,接受两个迭代器,表示区间[first, last],将这个区间排列成下一个较大的序列,如果当前区间已经是最大的序列(降序),则返回false。
next_permulation直接在原区间上更改,比如
#include <iostream>#include <algorithm>#include <vector>#include <iterator>int main(){ using namespace std; vector<int> nums{1, 2, 3, 4}; do { copy(nums.begin(), nums.end(), ostream_iterator<int>(cout, " ")); cout << endl; }while(next_permutation(nums.begin(), nums.end())); return 0;}
输出结果
1 2 3 4 1 2 4 3 1 3 2 4 1 3 4 2 1 4 2 3 1 4 3 2 2 1 3 4 ...4 2 3 1 4 3 1 2 4 3 2 1
注意next_permutation
每次只能找比当前序列大的下一个序列,如果没有就返回false
。并不是打印所有的排序。如果nums
初始化为{2, 1, 3, 4}
,那么就只会从{2, 1, 3, 4}
这个序列开始找,不会有{1, *, *, *}
这样的排列
题目要求就是实现next_permutation函数,返回当前序列的下一个序列(排列),要求比当前序列大,但是是所有可能的结果中最小的,比如说
寻找1 3 2的下一个排序返回的应该是2 1 3而不是2 3 1,因为2 1 3是所有可能中最小的
这也是next_permutation的规则,每次只找比当前排列大的所有可能的结果中最小的那个排列
既然要变大,又要让变大的幅度尽量小,就需要尽量让前面的数字保持不变,只改变后面几个的顺序。拿数字来说就是尽量只改变个位十位百位再往上的顺序,尽量不改变万位,十万位,百万位那些高位的顺序,这样才能让变大的幅度小一些。所以很显然要从后往前遍历。
思路如下,假设nums大小为n
- 从后向前遍历,i记录当前遍历到的位置
- 因为只有当递减时才没有更大的排序,所以[i + 1 : n)一定是递减的
- 如果[i + 1 : n)中有比nums[i]大的元素,找到最后一个比nums]i]大的元素(因为递减),与nums[i]互换位置
- 此时nums[i]已经比原先的nums[i]大,高位变大,低位应该尽量变得最小
- 将[i + 1 : n)逆序,因为以前递减,互换后仍然递减,为了变小,应该让后面序列递增
代码如下
class Solution {public: void nextPermutation(vector<int>& nums) { int n = nums.size(); /* 从倒数第二个开始,判断后面有没有比nums[i]大的数 */ for(int i = n - 2; i >= 0; --i) { /* 因为[i+1: n)是递减的,如果大于最大的那个,就说明不存在比nums[i]大的 */ if(nums[i] >= nums[i + 1]) continue; /* 二分查找找到最后一个比nums[i]大的位置 */ int j = binary_find(i + 1, n - 1, nums, nums[i]); /* 交换位置,让高位变大 */ swap(nums[i], nums[j]); /* 逆序,高位变大后,让低位变得最小 */ reverse(nums.begin() + i + 1, nums.end()); return; } /* 如果整个nums最开始就是递减的,那么没有更大的排序,变成最小的 */ reverse(nums.begin(), nums.end()); }private: /* 二分查找,找到最后一个大于n的位置 */ int binary_find(int left, int right, vector<int>& nums, int n) { /* * left左边一定都大于n,right右边一定都小于等于n。返回后left > right * 所以nums[right] > n, nums[left] <= n * 所以nums[right]就是最后一个大于n的数 */ while(left <= right) { int middle = (left + right) / 2; /* 防止无限循环,所有不管大于/小于都改变其中一个大小 */ /* 如果中间位置大于n,说明在右边,但是middle有可能也是最后的结果 */ if(nums[middle] > n) left = middle + 1; /* 如果小于等于n,说明在左边 */ else right = middle - 1; } return right; }};
阅读全文
0 0
- 每天一道LeetCode-----重新实现next_permutation
- 每天一道LeetCode-----KMP算法查找子串,重新实现strStr()函数
- 每天一道LeetCode-----重新实现开方运算sqrt(x),只返回整数部分即可
- 每天一道LeetCode----位运算实现加减乘除四则运算
- 每天一道LeetCode-----实现二叉搜索树的迭代器
- 每天一道LeetCode-----字符串乘法
- 每天一道LeetCode-----括号匹配
- 每天一道LeetCode-----数独盘求解
- 每天一道LeetCode-----生命游戏
- 每天一道leetcode题目_(1)
- 【每天一道leetcode】1:N-Queens
- 每天一道LeetCode-----回文链表
- 每天一道LeetCode-----n皇后问题
- 每天一道LeetCode-----化简路径
- 每天一道LeetCode-----逆序链表
- 【leetcode】 Permutations 一个简单next_permutation的实现
- next_permutation 实现
- 每天一道LeetCode-----最长无重复子串
- 独家 | 离开百度后,王劲创办的景驰将于2020年6月量产自动驾驶汽车
- 关于 android 中 postDelayed方法的讲解
- Social Net ZOJ
- Codeforces Round #443(Div.2) C.Short Program(位运算+思维)
- Java 正则表达式 常见的功能
- 每天一道LeetCode-----重新实现next_permutation
- Linux系统下常见的Xshell运行命令——Xshell入门必看
- Kotlin 基础语法-04
- Java 正则表达式 练习
- Java 简单多线程选号
- css样式 div板块与页面无边距
- 快速学习和掌握 IntelliJ IDEA 2017 的同学推荐一个教程
- java 简单爬虫练习
- php微信公众号支付接口开发demo