刷刷笔试题~~--[有关DFS的一些题]

1.全排列的一种求法

思路简述:

一个全排列其实就是一条把数组无重复遍历一遍的DFS过程

思路一:简单回溯,

1. 一个List存遍历路径,从第N个“结点”到第N+1个“结点”是只需要找一个未遍历的结点就行

2. 一个关键点在于查找 下一个可遍历“结点”, 可以用SET辅助List存放已遍历结点,List中存遍历书序(文中方法未用SET,复杂度较高,但是可以在Leetcode上AC);也可用一个数据结构完成:LinkedHashMap,即可保存插入顺序,也可O(1)判断是否存在某元素。

3. 回溯: 选中某一子“结点”递归下去之后,要回溯查找另一“子节点”,这就是回溯的过程,通过把某时刻路径中最后结点删除,添加下一“子节点”实现

代码


public List<List<Integer>> permute(int[] num) {  
        List<List<Integer>> res = new LinkedList<List<Integer>>();  
        if(num == null || num.length < 1) return res;  
        bt(res, new ArrayList<Integer>(), 0, num);  
        return res;  
    }  
      
    public void bt(List<List<Integer>> res, final List<Integer> cur, int now, int[] num){  
        int length = num.length;  
        if(cur.size() >= length) {  
            res.add(new ArrayList<Integer>(){  
                {  
                    addAll(cur);  
                }  
            });  
            return ;  
        }  
        for(int i = now; i < length || i % length < now; i++){//回溯  
            if(cur.contains(num[i % length])) continue;//判断回溯的元素是否已加入当前组合中  
            cur.add(num[i % length]);  
            bt(res, cur, (i  + 1)% length, num);  
            cur.remove(cur.size() - 1);  
        }  
    }  

拿num={1,2}来举例一下把

先放1进去,然后放2进去,这时候cur.size()=length,所以得到了一个正确答案{1,2},return

return出去后,之后的一条是cur.remove(cur.size()-1),移除掉最后一个元素,现在变成了{1}

很重要的是,这里有一个for循环!!!因为第二位只放进去过2,所以这次for循环想把1放进去,放之前判断一下这个回溯的元素是否已经在当前组合中了

发现1已经在了,这时也没有其他数可以加进去了,for循环结束,此次的小递归又结束了一个

然后还是cur.remove(cur.size()-1),把1页移除了,现在变成{ }

然后for循环往里面放2,在放1,又得到一个正确答案,{2,1}

然后依旧删除最后一个数1,for循环想放2,发现已经有2了,结束一个小递归后再把1删除,这时,第一位,1和2都放过了,彻底结束



2.二叉树中和为某一值的路径【!!!】
题目描述
输入一颗二叉树和一个整数,打印出二叉树中结点值的和为输入整数的所有路径。
路径定义为从树的根结点开始往下一直到叶结点所经过的结点形成一条路径。


import java.util.ArrayList;  
/** 
public class TreeNode { 
    int val = 0; 
    TreeNode left = null; 
    TreeNode right = null; 
 
    public TreeNode(int val) { 
        this.val = val; 
 
    } 
 
} 
*/  
public class Solution {  
    public ArrayList<ArrayList<Integer>> FindPath(TreeNode root,int target) {  
        ArrayList<ArrayList<Integer>> paths=new ArrayList<ArrayList<Integer>>();  
        if(root==null)  
            return paths;  
        find(paths,new ArrayList<Integer>(),root,target);  
        return paths;  
    }  
    public void find(ArrayList<ArrayList<Integer>> paths,ArrayList<Integer> path,TreeNode root,int target){  
        if(root==null)  
            return;  
        path.add(root.val);  
        if(root.left==null&&root.right==null&&target==root.val){  
            paths.add(path);  
            return;  
        }  
        ArrayList<Integer> path2=new ArrayList<Integer>();  
        path2.addAll(path);  
        find(paths,path,root.left,target-root.val);  
        find(paths,path2,root.right,target-root.val);  
          
    }  
}  

import java.util.ArrayList;  
/** 
public class TreeNode { 
    int val = 0; 
    TreeNode left = null; 
    TreeNode right = null; 
 
    public TreeNode(int val) { 
        this.val = val; 
 
    } 
 
} 
*/  
  
public class Solution {  
    private ArrayList<ArrayList<Integer>> listAll=new ArrayList<ArrayList<Integer>>();  
    private ArrayList<Integer> list=new ArrayList<Integer>();//声明在外面,因为一直要用  
    public ArrayList<ArrayList<Integer>> FindPath(TreeNode root,int target) {  
        //递推到最后的叶节点时要用到  
        if(root==null){  
            return listAll;  
        }  
        //遍历到这个节点,啥都不管先加到list里面  
        list.add(root.val);  
        target-=root.val;//更新target  
        //这是说明到达符合要求的叶节点了  
        if(target==0&&root.left==null&&root.right==null){  
            listAll.add(new ArrayList<Integer>(list));//新new一个list,原来的list还要一直用  
        }  
        //向下找左子树右子树  
        FindPath(root.right,target);  
        FindPath(root.left,target);  
        //遍历到叶节点不符合要求,把它在list里面删掉,回退,然后再继续递归遍历  
        list.remove(list.size()-1);  
        return listAll;  
    }  
}  



















  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值