46. A buckle arrangement full force LeetCode

Title Description (medium difficulty)

Description is very simple, it is given a few numbers, then output all their possible permutations.

Solution insert a

This is a method he started to think of the idea to consider is, first consider how to solve small problems, then use a small problem to solve big problems. Yes, that is the idea of ​​recursion. For example,

If there is only one digit [1], then it is simple, direct return [[1]] OK.

If you added a 1, 2, [12] how to do it? We only need the top of the case, in the gap of 1, that is, the right to the left inserted 2 is enough. Becomes [[ 2 1], [1 2 ]].

If we add a number 3, [123] how to do it? Similarly, we only need to insert numbers in all cases where the gap in the top 3 on the line. For example, [21] on the left, middle and right insert 3, into 3 2 1,2 3 1,2 1 3 . Similarly, 12 on the left, middle and right insert 3, into three . 1 2,1 3 2,1 2 3 , the final result is the [[321], [231], [213 ], [312], [132], [123]].

If we add numbers it is the same reason, just before the case, the digital gap is enough to insert a new figure.

With the idea of ​​a direct look at the code.

public List<List<Integer>> permute(int[] nums) {
    return permute_end(nums,nums.length-1);
}
// end 表示当前新增的数字的位置
private List<List<Integer>> permute_end(int[] nums, int end) {
    // 只有一个数字的时候
    if(end == 0){
        List<List<Integer>> all = new ArrayList<>();
        List<Integer> temp = new ArrayList<>();
        temp.add(nums[0]);
        all.add(temp);
        return all;
    }
    //得到上次所有的结果
    List<List<Integer>> all_end = permute_end(nums,end-1);
    int current_size = all_end.size();
    //遍历每一种情况
    for (int j = 0; j < current_size; j  ) { 
        //在数字的缝隙插入新的数字
        for (int k = 0; k <= end; k  ) {
            List<Integer> temp = new ArrayList<>(all_end.get(j));
            temp.add(k, nums[end]);
            //添加到结果中
            all_end.add(temp);
        };

    }
    //由于 all_end 此时既保存了之前的结果,和添加完的结果,所以把之前的结果要删除
    for (int j = 0; j < current_size; j  ) {
        all_end.remove(0);
    }
    return all_end;
}

Since there is a recursive process, we can also directly into iterative, recursive can begin the process of constantly push omitted.

public List<List<Integer>> permute(int[] nums) {
    List<List<Integer>> all = new ArrayList<>();
    all.add(new ArrayList<>());
    //在上边的基础上只加上最外层的 for 循环就够了,代表每次新添加的数字
    for (int i = 0; i < nums.length; i  ) {
        int current_size = all.size();
        for (int j = 0; j < current_size; j  ) {
            for (int k = 0; k <= i; k  ) {
                List<Integer> temp = new ArrayList<>(all.get(j));
                temp.add(k, nums[i]);
                all.add(temp);
            }
        }
        for (int j = 0; j < current_size; j  ) {
            all.remove(0);
        }
    }
    return all;
}

Time complexity, if only the analysis of the code words quite complex. If the final result, it should be n! A result, it should be a time complexity O (n!).

Complexity Space: O (1).

Solution two back

The start did not think the reference here .

In fact, it can be considered quite typical of backtracking recursive each time you add a number to the temp, the numbers add enough to come back later backtracking again after adding a new solution.

Can be understood as one layer is added, each layer is a for loop.

Call each one enters a for loop, the equivalent lists all solution, and then pick up what we need. In fact, in essence, depth-first traversal DFS.

public List<List<Integer>> permute(int[] nums) {
   List<List<Integer>> list = new ArrayList<>(); 
   backtrack(list, new ArrayList<>(), nums);
   return list;
}

private void backtrack(List<List<Integer>> list, List<Integer> tempList, int [] nums){
   if(tempList.size() == nums.length){
      list.add(new ArrayList<>(tempList));
   } else{
      for(int i = 0; i < nums.length; i  ){ 
         if(tempList.contains(nums[i])) continue; // 已经存在的元素,跳过
         tempList.add(nums[i]); //将当前元素加入
         backtrack(list, tempList, nums); //向后继续添加
         tempList.remove(tempList.size() - 1); //将 tempList 刚添加的元素,去掉,尝试新的元素
      }
   }
} 

time complexity:

Space complexity:

Solution three exchange

Reference [here] (https://leetcode.com/problems/permutations/discuss/18247/My-elegant-recursive-C -solution-with-inline-explanation? OrderBy = most_votes).

The idea is very cool, and a solution before the first recursive, dynamic programming little meaning, to a digital solution, the solution two digits, three digits solution, seek out a ring set a ring .

Suppose a function may be implemented subject to the requirement that all combinations nums generated and added to all the array. But it is one more parameter, begin, that is, only the specified number from nums [begin] to start the digital front fixed.

upset(int[] nums, int begin, List<List<Integer>> all)

If there is such a function, then everything is simple.

If you begin equal to the length of nums, it means that the number before the begin all the same, that is, all the numbers the same, we just need to add it to all on the line.

if (begin == nums.length) {
    ArrayList<Integer> temp = new ArrayList<Integer>(); 
    for (int i = 0; i < nums.length; i  ) {
        temp.add(nums[i]);
    }
    all.add(new ArrayList<Integer>(temp));
    return;
}

If other cases, we actually only need to use a for loop to begin into each number once, and then change numbers behind enough, is upset function call, all combinations begin 1 from the beginning.

for (int i = begin; i < nums.length; i  ) {
    swap(nums, i, begin);
    upset(nums, begin   1, all);
    swap(nums, i, begin);
}

Overall is the case.

public List<List<Integer>> permute(int[] nums) {
    List<List<Integer>> all = new ArrayList<>();
    //从下标 0 开始的所有组合
    upset(nums, 0, all);
    return all;
}

private void upset(int[] nums, int begin, List<List<Integer>> all) {
    if (begin == nums.length) {
        ArrayList<Integer> temp = new ArrayList<Integer>(); 
        for (int i = 0; i < nums.length; i  ) {
            temp.add(nums[i]);
        }
        all.add(new ArrayList<Integer>(temp));
        return;
    }
    for (int i = begin; i < nums.length; i  ) {
        swap(nums, i, begin);
        upset(nums, begin   1, all);
        swap(nums, i, begin);
    }

}

private void swap(int[] nums, int i, int begin) {
    int temp = nums[i];
    nums[i] = nums[begin];
    nums[begin] = temp;
}

time complexity:

Space complexity:

total

This question is very classic, dynamic programming, backtracking, recursion implementations again, of course, to force a recursive solution for a moment, and really pales compared to three solution, a recursive solution three is authentic, simple and elegant.

For more detailed explanations of popular leetcode.wang .

发布了61 篇原创文章 · 获赞 7 · 访问量 2万+

Guess you like

Origin blog.csdn.net/wind_liang/article/details/104029950