队列的算法相关专题

同样,这里也以一道题目为切入点

队列的算法相关专题_第1张图片
这题看似和队列没啥关系,但是涉及到图的广度优先遍历,我们可以构造出一个关系图:

队列的算法相关专题_第2张图片
拿6举例子,和2之间相差4,和5相差1,都是平方数,此图就是由相隔平方数构成。

class Solution {
     
    public int numSquares(int n) {
     
       Queue<Pair> queue = new LinkedList<>();
       queue.offer(new Pair(n,0));
       if(n == 0) return 0;
       while(!queue.isEmpty()){
     
           int num = queue.peek().x;
           int step = queue.poll().y;
           if(num == 0) return step; // 当剩余数为0,表示已经得到结果了,因为是广度优先遍历,得到的结果一定是最短的路径
           for(int i = 1; num - i*i >= 0; i++){
     
               queue.offer(new Pair(num-i*i,step+1));  // 把剩余的数字放入进来,步骤+1
           }
       }
       return -1;  // 绝对不会执行到这里
    }
}
class Pair{
     
    public int x;  // x为剩余数字,y为 step
    public int y;
    public Pair(int x, int y){
     
        this.x = x;
        this.y = y;
    }
}

结果发现悲催的超时了…,思路是没错的,改进改进:AC:

class Solution {
     
    public int numSquares(int n) {
     
       Queue<Pair> queue = new LinkedList<>();
       Map<Integer,Integer> map = new HashMap<>();  // 记录哪些已经计算过了
       queue.offer(new Pair(n,0));
       if(n == 0) return 0;
       while(!queue.isEmpty()){
     
           int num = queue.peek().x;
           int step = queue.poll().y;
           if(num == 0) return step;
           for(int i = 1; num - i*i >= 0; i++)
               if(map.get(num - i*i) == null){
     
                    queue.offer(new Pair(num-i*i,step+1));
                    map.put(num-i*i,1);
               }  
       }
       return -1;
    }
}
class Pair{
     
    public int x;
    public int y;
    public Pair(int x, int y){
     
        this.x = x;
        this.y = y;
    }
}

下面这种也是可以AC的:

class Solution {
     
    HashMap<Integer,Integer> map = new HashMap();
    public int numSquares(int n) {
     
        int val = (int)Math.sqrt(n);
        if(val*val == n) return 1;
        if(map.get(n) != null) return map.get(n);
        int res = Integer.MAX_VALUE;
        for(int i = 1; i*i<n;i++)
            res = Math.min(res,1+numSquares(n-i*i));
        map.put(n,res);
        return res;
    }
}

每次保存n和step的关系,防止重复查找,大大减少计算量。


再来一个

队列的算法相关专题_第3张图片
这题,可以用DFS解决,也可以用BFS解决,因为这集是队列,所以用BFS来计算:

访问每个节点,保存根节点到该节点的路径,当到叶子节点时,判断路径和是否等于sum,本质上就是一个层序遍历的过程

class Solution {
     
    
    public List<List<Integer>> pathSum(TreeNode root, int sum) {
     
        List<List<Integer>> res = new ArrayList<>();
        if(root == null) return res;
        Deque<TreeNode> deque = new LinkedList<>();
        deque.offerLast(root);
        Map<TreeNode,List<Integer>> map = new HashMap<>();
        List<Integer> w = new ArrayList<>();
        w.add(root.val);
        map.put(root, w);
        while(!deque.isEmpty()){
      
            TreeNode node = deque.pollFirst();
            if(node.left == null && node.right == null){
       // 到了叶子节点
                int u = 0;
                for(int i = 0; i<map.get(node).size(); i++){
     
                    u += map.get(node).get(i);
                }
                if(u == sum) res.add(map.get(node));
            }
            if(node.left != null){
     
                List<Integer> r = new ArrayList<>();  // 这里注意list的复制
                r.addAll(map.get(node));
                r.add(node.left.val);
                map.put(node.left,r);
                deque.offerLast(node.left);
            }
            if(node.right != null){
     
                List<Integer> r = new ArrayList<>();
                r.addAll(map.get(node));
                r.add(node.right.val);
                map.put(node.right,r);
                deque.offerLast(node.right);
            }
        }
        return res;
    }
}

你可能感兴趣的:(大厂面试算法指南,算法以及数据结构,队列,广度优先,算法,leetcode)