给定一个数组,数组中的元素不重复,将数组中的元素全排列,输出全排列的组合。
Input: [1,2,3]
Output:
[
[1,2,3],
[1,3,2],
[2,1,3],
[2,3,1],
[3,1,2],
[3,2,1]
]
思路:(回溯 + 深度优先搜索)
利用递归,将数组的下标元素不断的交换,记录下标变动的位置,当下标到达最后一个位置时,则将此时的数组加入到答案中。程序返回后,将之前变动交换的数组再交换回来,回复原状。详见Grandyang。
class Solution { public: vector<vector<int>> permute(vector<int>& nums) { vector<vector<int>> res; permuteDFS(nums, 0, res); return res; } void permuteDFS(vector<int>& nums, int start, vector<vector<int>>& res) { if (start == (int)nums.size()) { res.push_back(nums); return; } for (int i = start; i < (int)nums.size(); i++) { swap(nums[start], nums[i]); permuteDFS(nums, start + 1, res); swap(nums[start], nums[i]); } } };
Java 版:
• 深搜 + 回溯 的算法,回溯时重置现场,开启新一轮深搜;
• 将数组的下标元素,不断的枚举交换,当下标到达最后一个位置时,将此时的数组,加入到结果集;
• 注意:交换后迭代时,更新的是 start + 1,而不是 i+ 1;
• 因为:基于首元素的交换,将 start 后面的值,不断的与首元素 nums[start] 交换,当后面所有的元素都与 start 交换完后,移动 start,再将后面的所有元素,都来与 nums[start] 交换,这样就能穷举完所有可能的排列。
• 如果是用 i+1 ,比如:[1,2,3] 当 start = 0, i=1 时,交换后变为 [2,1,3],此时若使用 i+1,start = 2,由于 start 只能和大于等于他的下标交换,则只能得到 [2,1,3] 而得不到 [2,3,1] 这个答案。有的人可能会想:那我 start=0, i=0,此时 i+1就可以取到 start=1 了,但是此时数组最前面是 [1,*,*] 以 1 开头,而对于 [2,*,*] 这种以 2 开头的数,就有错误了!!!
class Solution { public List<List<Integer>> permute(int[] nums) { List<List<Integer>> res = new ArrayList<>(); permuteDFS(nums, 0, res); return res; } private void permuteDFS(int[] nums, int start, List<List<Integer>> res){ if(start == nums.length){ List<Integer> tmp = new ArrayList<>(); // int 数组转为 List<Integer> for(int a : nums) tmp.add(a); res.add(tmp); return; // 加入结果集,返回上一层 } for(int i = start; i < nums.length; i++){ int number = nums[start]; // 交换两个下标的值 nums[start] = nums[i]; nums[i] = number; permuteDFS(nums, start + 1, res); // 注意这儿是 start + 1,而不是 i+1 nums[i] = nums[start]; // 恢复原状,交换回来 nums[start] = number; } } }