31. Next Permutation
题目
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
一开始题目没有看懂,所以在网上搜了解释。根据百度知道:zhidao.baidu.com/question/530315721.html,C++有一个函数叫做boolean next_permutation(a.begin(),a.end()) ,
该函数是以输入字符串中的字符所构建的按字典顺序全排列中,判断当前字符串之后是否还有下一个字符串
如果next_permutation的执行次数少于全排列的个数,返回true
例如 a=”abc” 全排列有 “abc” “acb” “bac” “bca” “cab” “cba”
执行一次next_permutation 返回true a变成 “acb”
再执行一次next_permutation 返回true a变成 “bac”
…
当执行到a=”cba” 时 由于这已经是全排列的最后一个字符串,所以 再次执行next_permutation 则返回false。
思路
利用递归,每次如果数组大小大于1,则继续递归查找子数组是否可以进行排列,如果不能进行排列。则将本身与子数组中比自己大且与自己最接近的数组进行交换并且将子数组排序(由于子数组的顺序一定是从大到小排列,所以可以从尾部进行查找),如果子数组中没有数比本身大,则包括本身的数组也不能进行排列。
代码
class Solution {
public:
void nextPermutation(vector<int>& nums) {
//如果数组大小小于等于1,则不需要排序
if (nums.size()<2) {
return;
}
//如果整个数组无法排序,则按照题目要求从小到大排列
if (helper(nums, 0) == -1) {
sort(nums.begin(), nums.end());
}
}
int helper(vector<int>& nums, int start) {
//如果还有子数组,先进行子数组的递归。
if (start == nums.size()-1) {
return -1;
}
if (helper(nums, start + 1) == -1) {
for (int i = nums.size() - 1; i >= start + 1; i--) {
if (nums[start] < nums[i]) {
swap(nums[start], nums[i]);
sort(nums.begin()+start+1, nums.end());
return 1;
}
}
return -1;
}
return 1;
}
};
46. Permutations
题目
Given a collection of distinct numbers, return all possible permutations.
For example,
[1,2,3] have the following permutations:
[
[1,2,3],
[1,3,2],
[2,1,3],
[2,3,1],
[3,1,2],
[3,2,1]
]
Solution 1
思路
本来想直接用31题的代码得到下一个排列,但是效率好像偏低。C++有一个库函数next_permutation(copy.begin(), copy.end()),可以直接用,所以代码很简单啦!先给num排序,就不用考虑如果排序到结尾的问题。
代码
class Solution {
public:
vector<vector<int>> permute(vector<int>& nums) {
vector<vector<int>> result;
vector<int> copy = nums;
sort(copy.begin(), copy.end());
result.push_back(copy);
while (next_permutation(copy.begin(), copy.end())) {
result.push_back(copy);
}
return result;
}
};
Solution 2 [参照LeetCode上的solution]
思路
链接:A general approach to backtracking questions in Java (Subsets, Permutations, Combination Sum, Palindrome Partioning)
利用递归思想,每次依照顺序选择数组nums中的一个填入相应的位置,然后继续寻找每一个不相同的元素填入下一个位置,以此类推,得出可能的排列。
代码
class Solution {
public:
vector<vector<int>> permute(vector<int>& nums) {
vector<vector<int>> result;
vector<int> temp;
backtrack(result, temp, nums);
return result;
}
void backtrack(vector<vector<int>>& result, vector<int>& temp, vector<int>& nums) {
if (temp.size() == nums.size()) {
result.push_back(temp);
} else {
for (int i = 0; i < nums.size(); i++) {
if (find(temp.begin(), temp.end(), nums[i]) != temp.end()) {
continue;
}
temp.push_back(nums[i]);
backtrack(result, temp, nums);
temp.erase(temp.end()-1);
}
}
}
};
Solution 3 [参照LeetCode上的solution]
思路
链接:My elegant recursive C++ solution with inline explanation
利用递归思想,每次交换nums数组begin位的数和遍历到的数,然后对begin位以后的数组进行处理,然后交换回来,保持nums数组顺序不变。这种思路是我认为最好理解也最简单的思路。
代码
class Solution {
public:
vector<vector<int> > permute(vector<int> &num) {
vector<vector<int> > result;
permuteRecursive(num, 0, result);
return result;
}
// permute num[begin..end]
// invariant: num[0..begin-1] have been fixed/permuted
void permuteRecursive(vector<int> &num, int begin, vector<vector<int> > &result) {
if (begin >= num.size()) {
// one permutation instance
result.push_back(num);
return;
}
for (int i = begin; i < num.size(); i++) {
swap(num[begin], num[i]);
permuteRecursive(num, begin + 1, result);
// reset
swap(num[begin], num[i]);
}
}
};