更好理解回溯算法的全排列,详细执行流程

全排列

刚遇到这道题,对回溯算法不熟悉的我,真的太难了。虽然对深度遍历还是有一点理解的。

做完这道题,我感觉对回溯算法有了更好的理解

想看完整代码,可以直接拉到最后

下面我是逐个代码块分析

下面的这顿代码是主程序入口,为了模拟用。

public static void main(String[] args) {
    int[] arr = new int[]{1,2,3};
    List<List<Integer>> permute = permute(arr);
    System.out.println(permute.toString());
}

首先leetcode给出的方法返回值是 List<List>,所以,我们就需要弄个这样的list出来,也就是存储数组中的数组

List inlist = new ArrayList<>(); 存储数组

boolean[] user = new boolean[nums.length]; 用来标记数组中某个数,有没有用过

dfs(nums,list,0,inlist,user); 深度遍历。从0开始,相当于 空。因为下面的分支是1 、2、3

    public static List<List<Integer>> permute(int[] nums) {
         List<List<Integer>> list = new ArrayList<>();    
         List<Integer> inlist = new ArrayList<>();
         boolean[] user = new boolean[nums.length];
         dfs(nums,list,0,inlist,user);
          return list;
    }

下面就是代码的核心了

当数组的长度为3,则放进去,存储起来,然后回溯一下。改变的是k值

 if (nums.length==k){
             list.add(new ArrayList<>(inlist));
             return;
        }

核心思想:

先进行

for循环,遍历数组里面的元素,第一个标记为true,然后添加进数组,进行dfs,不满足nums.length==k的条件,

for循环数组三个数字,因为第二个为true了,所以i变为1,进行dfs,不满足nums.length==k的条件,

for循环数组三个数字,因为第三个为true了,所以i变为2, 第三个标记为true, 存进去。进行dfs,nums.length==k的条件,存进去。

retrun 返回。k=2.

   user[i]=false;
   inlist.remove(inlist.size()-1);i=2,所以退出

然后执行了这两步,最后

退出第三个次循环 , 跳出dfs,各项数值回到第二次循环

 user[i]=false;
 inlist.remove(inlist.size()-1);

这时候,inlist只有1了,只有 user[1]为true,后面进行第二次循环,进行了i++之后,变成了i=2,所以,进去的是3

inlist=[1,3],后面,又跳出第二次循环,回到第一次循环。此时第一个循环是数值为1,3下标对应为true,所以循环,只有2进去。

形成数组inlist=[1,2,3].

后面以此类推。

 public static  void  dfs(int[] nums, List<List<Integer>> list,int k,List<Integer> inlist,  boolean[] user){
           if (nums.length==k){
                 list.add(new ArrayList<>(inlist));
                 return;
            }
           for (int i=0;i<nums.length;i++){
                if (!user[i]){
                   user[i]=true;
                   inlist.add(nums[i]);
                   dfs(nums,list,k+1,inlist,user);
                   user[i]=false;
                   inlist.remove(inlist.size()-1);
                                   }

}

完整代码

package com.wu.leetcode;

import java.util.ArrayList;
import java.util.List;


//输入:nums = [1,2,3]
//        输出:[[1,2,3],[1,3,2],[2,1,3],[2,3,1],[3,1,2],[3,2,1]]
public class 全排列 {
    public static void main(String[] args) {
        int[] arr = new int[]{1,2,3};
        List<List<Integer>> permute = permute(arr);
        System.out.println(permute.toString());
    }
        public static List<List<Integer>> permute(int[] nums) {
             List<List<Integer>> list = new ArrayList<>();
             List<Integer> inlist = new ArrayList<>();
             boolean[] user = new boolean[nums.length];
             dfs(nums,list,0,inlist,user);
              return list;
        }

        public static  void  dfs(int[] nums, List<List<Integer>> list,int k,List<Integer> inlist,  boolean[] user){
               if (nums.length==k){
                     list.add(new ArrayList<>(inlist));
                     return;
                }
               for (int i=0;i<nums.length;i++){
                    if (!user[i]){
                       user[i]=true;
                       inlist.add(nums[i]);
                       dfs(nums,list,k+1,inlist,user);
                       user[i]=false;
                       inlist.remove(inlist.size()-1);


                   }
               }

    }

    }
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值