Permutations

描述

Given a collection of 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], and [3,2,1].

next_permutation()

函数 next_permutation()的具体实现见这节 Next Permutation

  1. // Permutations
  2. // 重新实现 next_permutation()
  3. // 时间复杂度O(n!),空间复杂度O(1)
  4. public class Solution {
  5. public List<List<Integer>> permute(int[] nums) {
  6. List<List<Integer>> result = new ArrayList<>();
  7. Arrays.sort(nums);
  8. do {
  9. ArrayList<Integer> one = new ArrayList<>();
  10. for (int i : nums) {
  11. one.add(i);
  12. }
  13. result.add(one);
  14. // 调用的是 2.1.12 节的 next_permutation()
  15. // 而不是 std::next_permutation()
  16. } while(nextPermutation(nums, 0, nums.length));
  17. return result;
  18. }
  19. // 代码来自 2.1.12 节的 next_permutation()
  20. private static boolean nextPermutation(int[] nums, int begin, int end) {
  21. // From right to left, find the first digit(partitionNumber)
  22. // which violates the increase trend
  23. int p = end - 2;
  24. while (p > -1 && nums[p] >= nums[p + 1]) --p;
  25. // If not found, which means current sequence is already the largest
  26. // permutation, then rearrange to the first permutation and return false
  27. if(p == -1) {
  28. reverse(nums, begin, end);
  29. return false;
  30. }
  31. // From right to left, find the first digit which is greater
  32. // than the partition number, call it changeNumber
  33. int c = end - 1;
  34. while (c > 0 && nums[c] <= nums[p]) --c;
  35. // Swap the partitionNumber and changeNumber
  36. swap(nums, p, c);
  37. // Reverse all the digits on the right of partitionNumber
  38. reverse(nums, p+1, end);
  39. return true;
  40. }
  41. private static void swap(int[] nums, int i, int j) {
  42. int tmp = nums[i];
  43. nums[i] = nums[j];
  44. nums[j] = tmp;
  45. }
  46. private static void reverse(int[] nums, int begin, int end) {
  47. end--;
  48. while (begin < end) {
  49. swap(nums, begin++, end--);
  50. }
  51. }
  52. }

递归

本题是求路径本身,求所有解,函数参数需要标记当前走到了哪步,还需要中间结果的引用,最终结果的引用。

扩展节点,每次从左到右,选一个没有出现过的元素。

本题不需要判重,因为状态装换图是一颗有层次的树。收敛条件是当前走到了最后一个元素。

代码

  1. // Permutations
  2. // 深搜,增量构造法
  3. // 时间复杂度O(n!),空间复杂度O(n)
  4. public class Solution {
  5. public List<List<Integer>> permute(int[] nums) {
  6. Arrays.sort(nums);
  7. List<List<Integer>> result = new ArrayList<>();
  8. List<Integer> path = new ArrayList<>(); // 中间结果
  9. dfs(nums, path, result);
  10. return result;
  11. }
  12. private static void dfs(int[] nums, List<Integer> path,
  13. List<List<Integer>> result) {
  14. if (path.size() == nums.length) { // 收敛条件
  15. result.add(new ArrayList<Integer>(path));
  16. return;
  17. }
  18. // 扩展状态
  19. for (int i : nums) {
  20. // 查找 i 是否在path 中出现过
  21. int pos = path.indexOf(i);
  22. if (pos == -1) {
  23. path.add(i);
  24. dfs(nums, path, result);
  25. path.remove(path.size() - 1);
  26. }
  27. }
  28. }
  29. }

相关题目

原文: https://soulmachine.gitbooks.io/algorithm-essentials/content/java/brute-force/permutations.html