zoukankan      html  css  js  c++  java
  • 树-leetcode做题笔记

    总结:对于二叉树的常见问题:

    当涉及到按层序遍历,对二叉树进行各种操作时,常常采用栈或队列来对每一层数据进行保存

    收获:对做题时常用的结构的方法进行了一下简要总结

    1.Queue

    Queue: 基本上,一个队列就是一个先入先出(FIFO)的数据结构

    Queue接口与List、Set同一级别,都是继承了Collection接口。LinkedList实现了Deque接 口。

    下表显示了jdk1.5中的阻塞队列的操作:

      add        增加一个元索                     如果队列已满,则抛出一个IIIegaISlabEepeplian异常
      remove   移除并返回队列头部的元素    如果队列为空,则抛出一个NoSuchElementException异常
      element  返回队列头部的元素             如果队列为空,则抛出一个NoSuchElementException异常
      offer       添加一个元素并返回true       如果队列已满,则返回false
      poll         移除并返问队列头部的元素    如果队列为空,则返回null
      peek       返回队列头部的元素             如果队列为空,则返回null
      put         添加一个元素                      如果队列满,则阻塞
      take        移除并返回队列头部的元素     如果队列为空,则阻塞

    remove、element、offer 、poll、peek 其实是属于Queue接口。 

    在日常做题时,能使用offer(),就不使用add()

    2.ArrayList

    ArrayList是Java集合框架中的一个重要的类,它继承于AbstractList,实现了List接口,是一个长度可变的集合,提供了增删改查的功能。集合中允许null的存在。ArrayList类还是实现了RandomAccess接口,可以对元素进行快速访问。实现了Serializable接口,说明ArrayList可以被序列化,还有Cloneable接口,可以被复制。和Vector不同的是,ArrayList不是线程安全的。

    size()              函数返回集合中元素的数量;

    isEmpty()          函数返回集合是否为空,检查size是否为0,即使容量不为0(没有元素)

    contains(Object o)  检查集合中是否包含给定的元素

    indexOf(Object o)    函数返回集合中给定元素的第一次出现的位置,如果没有就返回-1

    lastIndexOf(Object o) 函数返回给定元素最后一次出现的位置,如果没有就返回-1:

    toArray()              将集合转化为数组;

    get(int index)      返回指定位置的元素

    set(int index,E element)   设置给定位置的元素为给定的元素,然后返回原来的元素

    add(E e)    添加元素;

    add(int index,E element)    在指定位置添加元素

    remove(int index)      删除指定位置的元素,然后返回这个元素

    addAll(Collection<? extends E> c)    添加给定集合中的所有元素到集合中,从末尾开始添加

    removeRange(int fromIndex,int toIndex)    删除给定范围内的所有元素

    3.LinkedList

    ArrayList基于动态数组的实现,它长于随机访问元素,但是在中间插入和移除元素时较慢

    LinkedList基于链表实现,在List中间进行插入和删除的代价较低,提供了优化的顺序访问。LinkedList在随机访问方面相对比较慢,但是它的特性集较ArrayList更大。

    支持的基础操作
    getFirst() getLast() removeFirst() removeLast() addFirst() addLast()

     本题要用到的双端队列

    public boolean offerFirst(E e) {
        addFirst(e);
        return true;
    }
    public boolean offerLast(E e) {
        addLast(e);
        return true;
    }
    public E peekFirst() {
        if (size == 0)
            return null;
        return getFirst();
    }
    public E peekLast() {
        if (size == 0)
            return null;
        return getLast();
    }
    public E pollFirst() {
        if (size == 0)
            return null;
        return removeFirst();
    }
    public E pollLast() {
        if (size == 0)
            return null;
        return removeLast();
    }

    题目如下(按之字形层序遍历)

    Given a binary tree, return the zigzag level order traversal of its nodes' values. (ie, from left to right, then right to left for the next level and alternate between).

    For example:
    Given binary tree{3,9,20,#,#,15,7},

        3
       / 
      9  20
        /  
       15   7
    

    return its zigzag level order traversal as:

    [
      [3],
      [20,9],
      [15,7]
    ]
    对于这类问题,首先想到的是利用中序遍历来达到层序遍历的结果,然后依次对于间隔行进行翻转
     1 import java.util.*;
     2 public class Solution {
     3     public ArrayList<ArrayList<Integer>> zigzagLevelOrder(TreeNode root) {
     4         ArrayList<ArrayList<Integer>> res=new ArrayList<ArrayList<Integer>>();
     5         
     6        Queue<TreeNode> queue=new LinkedList<>();
     7         if(root==null) return res;
     8         queue.offer(root);
     9         ArrayList<TreeNode> tmp=new ArrayList<>();
    10         int k=0;
    11         while(!queue.isEmpty()){
    12             int size=queue.size();
    13             ArrayList<Integer> list=new ArrayList<>();
    14            
    15             for(int i=0;i<size;i++){
    16                 TreeNode node =queue.poll();
    17                 tmp.add(node);
    18                 list.add(node.val);
    19                    if(node.left!=null) queue.offer(node.left);
    20                 if(node.right!=null) queue.offer(node.right);                               
    21             }
    22             if(k%2==1){
    23                 Collections.reverse(list);
    24                 }
    25             
    26             k++;
    27             res.add(list);
    28         }
    29      
    30         return res;
    31     }
    32 }

     如果熟悉ArrayList的add(int index,E element)    函数,也可以利用将元素直接添加到list位置0处以替换上面代码中对应列表的翻转,如下:

     1 import java.util.*;
     2 public class Solution {
     3     public ArrayList<ArrayList<Integer>> zigzagLevelOrder(TreeNode root) {
     4         ArrayList<ArrayList<Integer>> res=new ArrayList<ArrayList<Integer>>();
     5         
     6        Queue<TreeNode> queue=new LinkedList<>();
     7         if(root==null) return res;
     8         queue.offer(root);
     9         ArrayList<TreeNode> tmp=new ArrayList<>();
    10         int k=0;
    11         while(!queue.isEmpty()){
    12             int size=queue.size();
    13             ArrayList<Integer> list=new ArrayList<>();
    14            
    15             for(int i=0;i<size;i++){
    16                 TreeNode node =queue.poll();
    17                 tmp.add(node);
    18                 if(k%2==0)  list.add(node.val);
    19                 if(k%2==1) list.add(0,node.val);
    20                    if(node.left!=null) queue.offer(node.left);
    21                 if(node.right!=null) queue.offer(node.right);                               
    22             }
    23           
    24             
    25             k++;
    26             res.add(list);
    27         }
    28      
    29         return res;
    30     }
    31 }

    如果,我们将整个操作仔细细想一下,发现也可以用两个栈相互配合,交替使用,依次保存本行和下一行的数据,也可以达到同样的效果,只是整个操作没有前面方法方便

     1 import java.util.*;
     2 public class Solution {
     3     public ArrayList<ArrayList<Integer>> zigzagLevelOrder(TreeNode root) {
     4 
     5           TreeNode c = root;
     6         ArrayList<ArrayList<Integer>> res = new ArrayList<ArrayList<Integer>>();
     7         if (c == null)
     8             return res;
     9         Stack<TreeNode> s1 = new Stack<TreeNode>();
    10         Stack<TreeNode> s2 = new Stack<TreeNode>();
    11         s1.push(root);
    12         while (!s1.isEmpty() || !s2.isEmpty()) {
    13             ArrayList<Integer> tmp = new ArrayList<Integer>();
    14             while (!s1.isEmpty()) {
    15                 //先用栈1保存第一行的数据,然后将下一行的节点数据保存到栈2
    16                 c = s1.pop();
    17                 tmp.add(c.val);
    18                 if (c.left != null)
    19                     s2.push(c.left);
    20                 if (c.right != null)
    21                     s2.push(c.right);
    22             }
    23             res.add(tmp);
    24             //将第一行的数据保存
    25             tmp = new ArrayList<Integer>();
    26             while (!s2.isEmpty()) {
    27                 //将栈2中的依次数据出栈,然后将其子节点推入栈1
    28                 //需要注意的是子节点入栈的顺序,因为是之字形遍历,所以对于上面的要从左到右的入栈,
    29                 //对于此处要从右到左的入栈
    30                 c = s2.pop();
    31                 tmp.add(c.val);
    32                 if (c.right != null)
    33                     s1.push(c.right);
    34                 if (c.left != null)
    35                     s1.push(c.left);
    36             }
    37             if (!tmp.isEmpty())
    38                 res.add(tmp);
    39         }
    40         return res;
    41     }
    42     }

     既然可以用两个栈来完成,那么也可以用队列再来试试,但显然用两个队列是不行的,但是我们可以使用一个双向队列来进行操作,同样AC

     1 import java.util.*;
     2 public class Solution {
     3     public ArrayList<ArrayList<Integer>> zigzagLevelOrder(TreeNode root) {
     4 
     5           TreeNode c = root;
     6         boolean flag=true;
     7         ArrayList<ArrayList<Integer>> res = new ArrayList<ArrayList<Integer>>();
     8         if (c == null)  return res;
     9         LinkedList<TreeNode> queue = new LinkedList<TreeNode>();
    10         queue.offerFirst(c);
    11        while(!queue.isEmpty()){
    12            ArrayList<Integer> list=new ArrayList<>();
    13            int size=queue.size();
    14            if(flag){
    15                    for(int i=0;i<size;i++){
    16                    TreeNode node=queue.pollFirst();
    17                    list.add(node.val);
    18              
    19                    if(node.left!=null) queue.offerLast(node.left);
    20                    if(node.right!=null) queue.offerLast(node.right);  }
    21                res.add(list);
    22                }else{
    23                        for(int i=0;i<size;i++){
    24                    TreeNode node=queue.pollLast();
    25                    list.add(node.val);
    26                            
    27                    if(node.right!=null) queue.offerFirst(node.right); 
    28                    if(node.left!=null) queue.offerFirst(node.left);
    29                      }
    30                res.add(list);
    31                        
    32                    }
    33            flag=!flag;
    34        }
    35    return res;
    36     }
    37 }
    38           

    资料参考:

    List的API

    ArrayList详解

    LinkedList 讲解

    java中的Queue

  • 相关阅读:
    Binary Tree Zigzag Level Order Traversal
    Binary Tree Level Order Traversal
    Symmetric Tree
    Best Time to Buy and Sell Stock II
    Best Time to Buy and Sell Stock
    Triangle
    Populating Next Right Pointers in Each Node II
    Pascal's Triangle II
    Pascal's Triangle
    Populating Next Right Pointers in Each Node
  • 原文地址:https://www.cnblogs.com/pathjh/p/8678931.html
Copyright © 2011-2022 走看看