算法-栈、队列、优先队列

目录

leetcode20-有效的括号

leetcode144-二叉树的前序遍历

leetcode102-二叉树的层次遍历

leetcode279-完全平法数

leetcode347-前k个高频元素

习题

leetcode150-逆波兰表达式求值

leetcode94-二叉树的中序遍历

leetcode145-二叉树的后序遍历

leetcode341-扁平化嵌套列表迭代器

leetcode107-二叉树的层次遍历

leetcode103-二叉树锯齿形层次遍历

leetcode199-二叉树的右视图


栈先进后出的特性;二叉数遍历递归和栈两种实现。stack:push,pop;queue:add(),poll();priorityQueue:add,remove,peek;二叉树的层序遍历:queue加count

leetcode20-有效的括号

给定一个只包括 '(',')','{','}','[',']' 的字符串,判断字符串是否有效。

有效字符串需满足:

左括号必须用相同类型的右括号闭合。
左括号必须以正确的顺序闭合。
注意空字符串可被认为是有效字符串。


思路:遇到左括号存入栈中,遇到右括号将栈中的第一个括号弹出进行匹配。

public boolean isValid(String s){
         if(s.length()==0){
             return true;
         }
         Stack<Character> stack = new Stack<>();
         //遍历s
         for(int i=0;i<s.length();i++){
             if(s.charAt(i)=='['||s.charAt(i)=='('||s.charAt(i)=='{'){
                 stack.push(s.charAt(i));
             }else{
                 if(stack.isEmpty()){
                     return false;
                 }else{
                     char c = stack.pop();
                     if(s.charAt(i)==']'&&c=='['){
                         continue;
                     }else if(s.charAt(i)==')'&&c=='('){
                         continue;
                     }else if(s.charAt(i)=='}'&&c=='{'){
                         continue;
                     }else{
                         return false;
                     }
                 }
             }
         }
         return stack.isEmpty();
     }

leetcode144-二叉树的前序遍历

给定一个二叉树,返回它的 前序 遍历。

 示例:

输入: [1,null,2,3]  
   1
    \
     2
    /
   3 

输出: [1,2,3]


思路:前序遍历:根节点->左子树->右子树。使用递归算法,依次将节点加入结果res中

//使用递归算法
    public List<Integer> preorderTraversal(TreeNode root){
        List<Integer> res = new ArrayList<>();
        preOrder(root,res);
        return res;
    }
    
    private void preOrder(TreeNode node,List<Integer> res){
       if(node == null){
           return;
       } 
        
       res.add(node.val);
       preOrder(node.left,res);
       preOrder(node.right,res);
    }

思路2:使用栈来进行遍历.将要处理的节点依次压入栈,再依次将节点取出,把值存入res,将其right和left压入栈,注意先right后left,先进后出,才能先处理left。

 //使用栈来遍历,依次将需要操作的数压入栈中
    public List<Integer> preorderTraversal(TreeNode root){
        List<Integer> res = new ArrayList<>();
        if(root==null){
            return res;
        }
        Stack<TreeNode> stack = new Stack<>();
        stack.push(root);
        while(!stack.isEmpty()){
            TreeNode temp = stack.pop();
            // System.out.print(temp.val);
            res.add(temp.val);
            if(temp.right!=null){
                stack.push(temp.right);
            }
            if(temp.left!=null){
                stack.push(temp.left);
            }
        }
        return res;
    }

leetcode102-二叉树的层次遍历

给定一个二叉树,返回其按层次遍历的节点值。 (即逐层地,从左到右访问所有节点)。

例如:
给定二叉树: [3,9,20,null,null,15,7],

    3
   / \
  9  20
    /  \
   15   7
返回其层次遍历结果:

[
  [3],
  [9,20],
  [15,7]
]


思路:将每一层要处理的节点放入queue中,记录每一层的节点数,当节点数为0时,进入下一次层。queue加入add 弹出poll

//使用队列,将每一层的节点加入queue中,记录每一层的queue的节点数量,处理完后数量为0说明到了下一层。
    public List<List<Integer>> levelOrder(TreeNode root){
        List<List<Integer>> res = new ArrayList<>();
        if(root==null){
            return res;
        }
        Queue<TreeNode> queue = new LinkedList<>();
        queue.add(root);
        while(!queue.isEmpty()){
            int count = queue.size();
            List<Integer> list = new ArrayList<Integer>();
            while(count>0){
                TreeNode temp = queue.poll();
                list.add(temp.val);
                if(temp.left!=null){
                queue.add(temp.left);
                }
                if(temp.right!=null){
                    queue.add(temp.right);
                }
                count--;
            }
            res.add(list);
        }
        return res;
    }

leetcode279-完全平法数

给定正整数 n,找到若干个完全平方数(比如 1, 4, 9, 16, ...)使得它们的和等于 n。你需要让组成和的完全平方数的个数最少。

示例 1:

输入: n = 12
输出: 3 
解释: 12 = 4 + 4 + 4.
示例 2:

输入: n = 13
输出: 2
解释: 13 = 4 + 9.


思路:将num-i*i的所有可能结果放入queue中,再从queue中取出num重复以上操作,当最先有num=0时,存在最短步数。

public int numSquares(int n) {
        if(n==0){
            return 0;
        }
        Queue<Integer> queue = new LinkedList<Integer>();
        queue.add(n);
        boolean[] visited = new boolean[n+1];
        visited[n] = true;
        int step = 0;
        while(!queue.isEmpty()){
            int count = queue.size();
            while(count>0){
                int num = queue.poll();
                if(num==0){
                    return step;
                }else{
                    for(int i=0;i*i<=num;i++){
                        if(visited[num-i*i]==false){
                            queue.add(num-i*i);
                            visited[num-i*i]=true;
                        }
                    }
                }
                count--;
            }
            step++;
        }
        return step;
    }

leetcode347-前k个高频元素

给定一个非空的整数数组,返回其中出现频率前 k 高的元素。

示例 1:

输入: nums = [1,1,1,2,2,3], k = 2
输出: [1,2]
示例 2:

输入: nums = [1], k = 1
输出: [1]
说明:

你可以假设给定的 k 总是合理的,且 1 ≤ k ≤ 数组中不相同的元素的个数。
你的算法的时间复杂度必须优于 O(n log n) , n 是数组的大小。


思路:使用优先队列存放前k个高频元素,优先队列的优先级由其出现的频率决定。

public List<Integer> topKFrequent(int[] nums, int k){
        List<Integer> res = new ArrayList<>();
        if(nums.length==0){
            return res;
        }
        //将每个元素出现的次数存入map中
        Map<Integer,Integer> map = new HashMap<>();
        for(int i=0;i<nums.length;i++){
            if(map.get(nums[i])==null){
                map.put(nums[i],1);
            }else{
                map.put(nums[i],map.get(nums[i])+1);
            }
        }
        
        //使用一个优先队列来存储频率前k高的元素,传入conparator
        PriorityQueue<Integer> queue = new PriorityQueue<>(new Comparator<Integer>(){
            @Override
            public int compare(Integer o1,Integer o2){
                return map.get(o1)-map.get(o2);
            }
        });
        
        //queue中只存放k个元素,遍历map将值放入queue中
        for(Integer key:map.keySet()){
            if(queue.size()<k){
                queue.add(key);
            }else if(map.get(key)>map.get(queue.peek())){
                queue.remove();
                queue.add(key);
            }
        }
        
        
        //将queue的值存入res中
        while(!queue.isEmpty()){
            res.add(queue.remove());
        }
        return res;
    }

习题

leetcode150-逆波兰表达式求值

根据逆波兰表示法,求表达式的值。

有效的运算符包括 +, -, *, / 。每个运算对象可以是整数,也可以是另一个逆波兰表达式。

说明:

整数除法只保留整数部分。
给定逆波兰表达式总是有效的。换句话说,表达式总会得出有效数值且不存在除数为 0 的情况。
示例 1:

输入: ["2", "1", "+", "3", "*"]
输出: 9
解释: ((2 + 1) * 3) = 9
示例 2:

输入: ["4", "13", "5", "/", "+"]
输出: 6
解释: (4 + (13 / 5)) = 6
示例 3:

输入: ["10", "6", "9", "3", "+", "-11", "*", "/", "*", "17", "+", "5", "+"]
输出: 22
解释: 
  ((10 * (6 / ((9 + 3) * -11))) + 17) + 5
= ((10 * (6 / (12 * -11))) + 17) + 5
= ((10 * (6 / -132)) + 17) + 5
= ((10 * 0) + 17) + 5
= (0 + 17) + 5
= 17 + 5
= 22


思路:将非运算符压入栈中,当遇到运算符时,取出栈中的两个数据进行运算,并将运算结果压入栈。注意String和int类型转换。int b = Integer.parseInt(stack.pop());String.valueOf(a+b)

public int evalRPN(String[] tokens) {
        //将数字存入一个栈,当遇到算术运算符,就弹出栈中的两个数进行运算,再将结果压入栈中
        Stack<String> stack = new Stack<>();
        for(int i=0;i<tokens.length;i++){
            if(!"+".equals(tokens[i])&&!"-".equals(tokens[i])&&!"*".equals(tokens[i])&&!"/".equals(tokens[i])){
                stack.push(tokens[i]);
            }else{
                int b = Integer.parseInt(stack.pop());
                int a = Integer.parseInt(stack.pop());
                if("+".equals(tokens[i])){
                    stack.push(String.valueOf(a+b));
                }
                if("-".equals(tokens[i])){
                    stack.push(String.valueOf(a-b));
                }
                if("*".equals(tokens[i])){
                   stack.push(String.valueOf(a*b));
                }
                if("/".equals(tokens[i])){
                    stack.push(String.valueOf(a/b));
                }                
            }
        }
        return Integer.parseInt(stack.pop());
    }

leetcode94-二叉树的中序遍历

给定一个二叉树,返回它的中序 遍历。

示例:

输入: [1,null,2,3]
   1
    \
     2
    /
   3

输出: [1,3,2]
进阶: 递归算法很简单,你可以通过迭代算法完成吗?


思路:递归实现

//递归实现
    public List<Integer> inorderTraversal(TreeNode root) {
        List<Integer> res = new ArrayList<>();
        if(root==null){
            return res;
        }
        inOrder(root,res);
        return res;
    }
    
    public void inOrder(TreeNode node,List<Integer> res){
        if(node==null){
            return;
        }
        
        if(node.left!=null){
            inOrder(node.left,res);
        }
        res.add(node.val);
        if(node.right!=null){
            inOrder(node.right,res);
        }
    }

思路2:非递归实现,先将左右左边的元素压入栈,再依次弹出,再将右边的元素压入栈,依次弹出

//非递归实现,使用栈
    public static List<Integer> inorderTraversal(TreeNode root){
        List<Integer> res = new ArrayList<>();
        if(root==null){
            return res;
        }
        Stack<TreeNode> stack = new Stack<>();
        TreeNode cur = root;
        while(!stack.isEmpty()||cur!=null){
            while (cur!=null){
                stack.push(cur);
                cur = cur.left;
            }
            cur = stack.pop();
            res.add(cur.val);
            cur = cur.right;
        }
        return res;
    }

leetcode145-二叉树的后序遍历

给定一个二叉树,返回它的 后序 遍历。

示例:

输入: [1,null,2,3]  
   1
    \
     2
    /
   3 

输出: [3,2,1]
进阶: 递归算法很简单,你可以通过迭代算法完成吗?。


思路:递归实现

//递归实现
    public List<Integer> postorderTraversal(TreeNode root) {
        List<Integer> res = new ArrayList<>();
        if(root==null){
            return res;
        }
        postOrder(root,res);
        return res;
    }
    private void postOrder(TreeNode node,List<Integer> res){
        if(node==null){
            return;
        }
        if(node.left!=null){
            postOrder(node.left,res);
        }
        if(node.right!=null){
            postOrder(node.right,res);
        }
        res.add(node.val);
    }

思路2:二叉树的前序遍历大家都会写吧,很简单,顺序是中左右。而二叉树的后序遍历顺序是左右中。于是可以把前序遍历左右调换一下,变成中右左,最后再整体reverse一下,不就变成左右中了

public List<Integer> postorderTraversal1(TreeNode root) {
        List<Integer> res = new ArrayList<>();
        if(root == null) return res;
        Stack<TreeNode> stack = new Stack<>();
        stack.push(root);

        while(!stack.isEmpty()){
            TreeNode cur = stack.pop();
            res.add(cur.val);
            if(cur.left != null){
                stack.push(cur.left);
            }
            if(cur.right != null){
                stack.push(cur.right);
            }
        }
        Collections.reverse(res);
        return res;
    }

leetcode341-扁平化嵌套列表迭代器

public class NestedIterator implements Iterator<Integer> {

    private int current = 0;
    private List<NestedInteger> nestedList;
    private NestedIterator it;
    
    
    public NestedIterator(List<NestedInteger> nestedList) {
        this.nestedList = nestedList;
    }

    @Override
    public Integer next() {
        if(it != null) {
            if(it.hasNext()){
                return it.next();
            }else{
                current++;
                it = null;
            }
        }
        NestedInteger integer = nestedList.get(current);
        if(integer.isInteger()) {
            current++;
            it = null;
            return integer.getInteger();
        }else{
            it = new NestedIterator(integer.getList());
            return next();
        }
    }

    @Override
    public boolean hasNext() {
        if(it != null) {
            if(it.hasNext())
                return true;
            current++;
            it = null;
        }
        if(current >= nestedList.size())
            return false;
        NestedInteger integer = nestedList.get(current);
        if(integer.isInteger()) {
            return true;
        }else{
            it = new NestedIterator(integer.getList());
            return hasNext();
        }
    }
}

leetcode107-二叉树的层次遍历

给定一个二叉树,返回其节点值自底向上的层次遍历。 (即按从叶子节点所在层到根节点所在的层,逐层从左向右遍历)

例如:
给定二叉树 [3,9,20,null,null,15,7],

    3
   / \
  9  20
    /  \
   15   7
返回其自底向上的层次遍历为:

[
  [15,7],
  [9,20],
  [3]
]


思路:使用Queue来存放要遍历的节点,count来控制每一层的数量。从叶子节点向根节点遍历,先用stack存储结果List,再将每个Listpop()存入最终结果中

public List<List<Integer>> levelOrderBottom(TreeNode root) {
        List<List<Integer>> res = new ArrayList<>();
        if(root==null){
            return res;
        }
        //先将结果存放在栈中
        Stack<List<Integer>> stack = new Stack<>();
        Queue<TreeNode> nodes = new LinkedList<>();
        nodes.add(root);
        while(nodes.size()!=0){
            int count = nodes.size();
            System.out.println(count+"   1");
            List<Integer> list = new ArrayList<>();
            while(count>0){
               TreeNode temp = nodes.poll();
               list.add(temp.val);
               System.out.println(temp.val+"   2");
               if(temp.left!=null){
                   System.out.println(temp.left.val+"  3");
                   nodes.add(temp.left);
               }
                if(temp.right!=null){
                    System.out.println(temp.right.val+"   4");
                    nodes.add(temp.right);
                }
                count--;
            }
            stack.push(list);
        }
        //将stack中的数据取出来依次放入结果中
        while(!stack.isEmpty()){
            res.add(stack.pop());
        }
        return res;
    }

leetcode103-二叉树锯齿形层次遍历

给定一个二叉树,返回其节点值的锯齿形层次遍历。(即先从左往右,再从右往左进行下一层遍历,以此类推,层与层之间交替进行)。

例如:
给定二叉树 [3,9,20,null,null,15,7],

    3
   / \
  9  20
    /  \
   15   7
返回锯齿形层次遍历如下:

[
  [3],
  [20,9],
  [15,7]
]


 思路:还是使用queue进行层次遍历,但是在将每一层的结果存入结果res中时,判断层数step。若为奇数层,直接加入,若为偶数层倒序再加入。奇数层的处理是在加入数据时先放入一个栈中,再依次弹出加入到list中。

public List<List<Integer>> zigzagLevelOrder(TreeNode root){
        List<List<Integer>> res = new ArrayList<>();
        if(root==null){
            return res;
        }
        Queue<TreeNode> queue = new LinkedList<>();
        int step = 0;
        queue.add(root);
        while(queue.size()!=0){
            int count = queue.size();
            List<Integer> list = new ArrayList<>();
            Stack<Integer> stack = new Stack<>();
            while(count>0){
                TreeNode node = queue.poll();
                if(step%2==0){
                    list.add(node.val);
                }else{
                    stack.push(node.val);
                }
                if(node.left!=null){
                    System.out.println(node.left.val+"   3");
                    queue.add(node.left);
                }
                if(node.right!=null){
                    System.out.println(node.right.val+"   4");
                    queue.add(node.right);
                }
                count--;
            }
            if(step%2==0){
                res.add(list);
            }else{
                List<Integer> temp = new ArrayList<>();
                while(!stack.isEmpty()){
                    temp.add(stack.pop());
                }
                res.add(temp);
            }
            step++;
        }
        return res;
        
    }

leetcode199-二叉树的右视图

给定一棵二叉树,想象自己站在它的右侧,按照从顶部到底部的顺序,返回从右侧所能看到的节点值。

示例:

输入: [1,2,3,null,5,null,4]
输出: [1, 3, 4]
解释:

   1            <---
 /   \
2     3         <---
 \     \
  5     4       <---


 思路:还是用层序遍历方法queue加count,只是在count==1的时候,将当前节点的值加入res中。

public List<Integer> rightSideView(TreeNode root) {
        List<Integer> res = new ArrayList<>();
        if(root==null){
            return res;
        }
        Queue<TreeNode> queue = new LinkedList<>();
        queue.add(root);
        while(queue.size()!=0){
            int count = queue.size();
            while(count>0){
                TreeNode node = queue.poll();
                if(count==1){
                    res.add(node.val);
                }
                if(node.left!=null){
                    queue.add(node.left);
                }
                if(node.right!=null){
                    queue.add(node.right);
                }
                count--;
            }
        }
        return res;
    }

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值