当前位置:   article > 正文

(JAVA版)leetcode算法之路树篇(一)树的遍历相关

(JAVA版)leetcode算法之路树篇(一)树的遍历相关

一、题目

树的遍历相关题目做了一共14道

其中这些是两颗树的遍历对比

100. 相同的树572. 另一棵树的子树101. 对称二叉树

都用的深度优先搜索递归进行,分布对比两棵树的节点来返回false or true。

相同的树

  1. class Solution {
  2. public boolean isSameTree(TreeNode p, TreeNode q) {
  3. if (p == null && q == null) {
  4. return true;
  5. } else if (p == null || q == null) {
  6. return false;
  7. } else if (p.val != q.val) {
  8. return false;
  9. } else {
  10. return isSameTree(p.left, q.left) && isSameTree(p.right, q.right);
  11. }
  12. }
  13. }

另一个树的子树

  1. class Solution {
  2. public boolean isSubtree(TreeNode root, TreeNode subRoot) {
  3. if(subRoot==null&&root==null)
  4. return true;
  5. else if(root==null)
  6. return false;
  7. if(root.val==subRoot.val)
  8. return isSubtree(root.left,subRoot.left)&&isSubtree(root.right,subRoot.right);
  9. return isSubtree(root.left,subRoot)||isSubtree(root.right,subRoot);
  10. }
  11. }

对称二叉树

  1. class Solution {
  2. public boolean isSymmetric(TreeNode root){
  3. return check(root.left,root.right);
  4. }
  5. boolean check(TreeNode p,TreeNode q){
  6. if(p==null&&q==null)
  7. return true;
  8. if(p==null||q==null)
  9. return false;
  10. if(p.val!=q.val)
  11. return false;
  12. return check(p.left,q.right)&&check(p.right,q.left);
  13. }
  14. }

这一类题目都能以节点是否为null和节点的值来当作结束递归的条件,当一个递归函数拥有类型不是void,可以尝试在return中进行递归。

简单代码

还有例如104. 二叉树的最大深度这道题一行代码就能解决

  1. class Solution {
  2. public int maxDepth(TreeNode root) {
  3. return root == null ? 0 : Math.max(this.maxDepth(root.left), this.maxDepth(root.right)) + 1;
  4. }
  5. }

110. 平衡二叉树则是通过先判断二叉树的深度再来递归判断

  1. class Solution {
  2. public boolean isBalanced(TreeNode root) {
  3. return root == null || Math.abs(depth(root.left) - depth(root.right)) <= 1 && isBalanced(root.right) && isBalanced(root.left);
  4. }
  5. public int depth(TreeNode root){
  6. return root==null?0:Math.max(depth(root.left),depth(root.right))+1;
  7. }
  8. }

前中后序遍历

226. 翻转二叉树

  1. class Solution {
  2. public TreeNode invertTree(TreeNode root) {
  3. if (root == null) {
  4. return null;
  5. }
  6. TreeNode temp = root.left;
  7. root.left = root.right;
  8. root.right = temp;
  9. invertTree(root.left);
  10. invertTree(root.right);
  11. return root;
  12. }
  13. }

还有一种写法

  1. class Solution {
  2. public TreeNode invertTree(TreeNode root) {
  3. if (root == null) {
  4. return null;
  5. }
  6. TreeNode left = invertTree(root.left);
  7. TreeNode right = invertTree(root.right);
  8. root.left = right;
  9. root.right = left;
  10. return root;
  11. }
  12. }

类似的题目543. 二叉树的直径

  1. class Solution {
  2. int max=-1;
  3. public int diameterOfBinaryTree(TreeNode root) {
  4. d(root);
  5. return max;
  6. }
  7. public int d(TreeNode root){
  8. if(root==null)
  9. return 0;
  10. int left=d(root.left);
  11. int right=d(root.right);
  12. if(max<left+right)
  13. max=left+right;
  14. return Math.max(left,right)+1;
  15. }
  16. }

563. 二叉树的坡度

  1. class Solution {
  2. int all=0;
  3. public int findTilt(TreeNode root) {
  4. d(root);
  5. return all;
  6. }
  7. public int d(TreeNode root){
  8. if(root==null)
  9. return 0;
  10. int left=d(root.left);
  11. int right=d(root.right);
  12. all+=Math.abs(left-right);
  13. return root.val+left+right;
  14. }
  15. }

还有一些题目都大差不差:112. 路径总和530. 二叉搜索树的最小绝对差637. 二叉树的层平均值653. 两数之和 IV - 输入二叉搜索树671. 二叉树中第二小的节点606. 根据二叉树创建字符串以上这些就是目前做过的二叉树遍历系列。

二、总结

树的遍历总体都比较简单,除去层次遍历和广度优先搜索,基本都是递归遍历+深度优先搜索,在遍历的过程去处理节点或者处理节点的左右子树,还有一种就是获取节点信息或者节点的左右子树的信息来判断

三、用到的Java知识

因为之前是用c++做的,现在转java很多东西不一样,所以记录一下


3.1 StringBuffer

内容可变的字符串类,使用StringBuffer来对字符串的内容进行动态操作,不会产生额外的对象。 初始时,默认是有16个字符来做为缓冲区


3.1.1 构造方法

new StringBuffer();

new StringBuffer(String);

new StringBuffer(int);

new StringBuffer(charSequence);


3.1.2 常用方法

append():在当前StringBuffer对象上,追加其他内容

capacity():返回当前容量

length():返回长度 

setCharAt(int,char):将给定索引位置的字符设置为第二个参数给定的值

reverse():将StringBuffer内容反转

delete(int,int):删除StringBuffer从指定索引开始(包含)到结束(不包含)的字符串

toString():将StringBuffer转成字符串 insert(int,Object):在指定索引位置,插入给定值 

replace(int,int,String):将指定的字符串替换到起始位置(包含)和结束位置(不包含)中

deleteCharAt(int):删除指定索引位置的字符


3.2 集合类Collection

3.2.1、List

List里存放的对象是有序的,同时也是可以重复的,List关注的是索引,拥有一系列和索引相关的方法,查询速度快。因为往list集合里插入或删除数据时,会伴随着后面数据的移动,所有插入删除数据速度慢


3.2.1.1、ArrayList

ArrayList: 是List的一个实现类,底层数据结构是数组

构造方法:

List<String> list=new ArrayList<>();

常用方法

  1. add(Object obj)#在集合后面加入元素,会返回一个boolean类型的值
  2. add(int index,Object obj)#在指定索引位置前面插入一个元素
  3. size()#获取当前集合中元素的个数
  4. isEmpty()#判断当前集合中是否为空
  5. clear()#从集合中删除所有元素
  6. addAll(Collection c)#在当前集合中加入另一个集合的元素,要求两个集合使用的泛型相同
  7. addAll(int index,Collection c)#在当前集合指定位置之前,加入另一个集合的元素
  8. remove(int index)#移除指定索引位置的元素,并将该元素返回
  9. remove(Object obj)#移除对应元素,如果有多个相同值,只移除第一个找到的元素,如果是整数类型,
  10. 要封装成包装类。返回boolean类型的值,是否移除成功
  11. removeAll(Collection c)#从当前集合中移除参数集合中所有包含的元素
  12. retainAll(Collection c)#在当前集合中保留参数集合中所有包含的元素
  13. conatins(Object o)#判断当前集合中是否包含给定参数的元素,返回boolean类型的值
  14. containsAll(Collection c)#判断当前集合中是否包含给定参数集合的所有元素
  15. toArray()#以正序方式,返回一个包含所有元素的对象数组
  16. indexOf(Object)#查找参数在当前集合中第一次出现的索引位置
  17. lastIndexOf(Object)#查找参数在当前集合最后一次出现的索引位置
  18. subList(int index,int end)#对当前集合进行截取,从起始位置(包含)截取到结束位置(不包含),返
  19. 回一个新的List集合
  20. iterator()#获取集合的迭代器
  21. listIterator()#获取集合的List迭代器
  22. set(int index,Object obj)#设置索引位置的元素为第2个参数数据

 

3.2.1.2、LinkedList

LinkedList的底层使用了 双向链表

构造方法

List<Integer> list1 = new LinkedList<>();

新增方法

  1. addFirst(Object):将给定元素插入链表的开头
  2. addLast(Object):将给定元素追加到链表的尾部
  3. getFirst():获取链表的头结点元素值
  4. getLst():获取链表的尾结点元素值
  5. removeFirst():移除链表的头结点,并返回其中的元素值
  6. removeLast(): 移除链表的尾结果,并返回其中的元素值

 3.2.1.3、Queue

在队列这种数据结构中,最先插入的元素将是最先被删除的元素;反之最后插入的元素将是最后被删除的元素,因此队列又称为“先进先出”(FIFO—first in first out)的线性表。树的层次遍历会用到

LinkedList类实现了Queue接口,因此我们可以把LinkedList当成Queue来用。

构造方法

 Queue<String> queue = new LinkedList<String>();

常用方法

  1. 压入元素(添加):add()、offer()
  2. 相同:未超出容量,从队尾压入元素,返回压入的那个元素。
  3. 区别:在超出容量时,add()方法会对抛出异常,offer()返回false
  4. 弹出元素(删除):remove()、poll()
  5. 相同:容量大于0的时候,删除并返回队头被删除的那个元素。
  6. 区别:在容量为0的时候,remove()会抛出异常,poll()返回false
  7. 获取队头元素(不删除):element()、peek()
  8. 相同:容量大于0的时候,都返回队头元素。但是不删除。
  9. 区别:容量为0的时候,element()会抛出异常,peek()返回null。

 


 

3.2.1.4、Stack

Stack的底层存储结构是数组,Stack的进出方式是后进先出,Stack实现了List接口。

构造方法

Stack<Integer> stack=new Stack<>();

常用方法 

  1. 把元素压栈:push(E);
  2. 把栈顶的元素“弹出”:pop();
  3. 取栈顶元素但不弹出:peek()。

3.2.1.5、Deque

双端队列是Java集合框架中的一种数据结构,它允许在队列两端进行元素的插入和删除操作。Deque可以看作是既支持队列操作,又支持栈操作的一种数据结构

构造方法

  1. Deque<Integer> deque = new ArrayDeque<>();基于数组实现的双端队列
  2. LinkedList<String> deque = new LinkedList<>();用linkedList模拟

常用方法 

  1. void addFirst(E e):在队列的头部插入元素。
  2. void addLast(E e):在队列的尾部插入元素。
  3. boolean offerFirst(E e):尝试在队列头部插入元素,如果成功返回true,否则返回false
  4. boolean offerLast(E e):尝试在队列尾部插入元素,如果成功返回true,否则返回false
  5. E removeFirst():移除并返回队列头部的元素,如果队列为空,则抛出异常。
  6. E removeLast():移除并返回队列尾部的元素,如果队列为空,则抛出异常。
  7. E pollFirst():移除并返回队列头部的元素,如果队列为空,则返回null
  8. E pollLast():移除并返回队列尾部的元素,如果队列为空,则返回null
  9. E getFirst():返回队列头部的元素,但不移除,如果队列为空,则抛出异常。
  10. E getLast():返回队列尾部的元素,但不移除,如果队列为空,则抛出异常。
  11. E peekFirst():返回队列头部的元素,但不移除,如果队列为空,则返回null
  12. E peekLast():返回队列尾部的元素,但不移除,如果队列为空,则返回null

3.2.2、Set

Set是一种集合类型,它用于存储不重复的元素


3.2.2.1、HashSet

底层使用HashMap,将数据存储到hashMap的key上面 特点:无序性,唯一性。 如果存储的数据具有相同的hashcode,则会调用equals方法再次进行比较 常用方法和List接口相同 没有List接口中的索引处理方式

构造方法

Set<String> set = new HashSet<>(); 

 常用方法

  1. 添加元素:add(E element) 方法用于向HashSet中添加元素。
  2. 删除元素:remove(Object element) 方法用于从HashSet中删除指定的元素。
  3. 判断元素是否存在:contains(Object element) 方法用于判断HashSet中是否包含指定的元素。
  4. 获取集合大小:size() 方法用于获取HashSet中元素的数量。
  5. 判断集合是否为空:isEmpty() 方法用于判断HashSet是否为空。
  6. 清空集合:clear() 方法用于清空HashSet中的所有元素。

 3.2.2.2、TreeSet

底层是基于红黑树实现的有序集合

红黑树属性:

  1. 每个节点都有一个颜色属性,可以是红色黑色
  2. 根节点黑色的。
  3. 每个叶子节点(NIL 节点,在 TreeSet 的实现中可能不显式表示)是黑色的。
  4. 如果一个节点是红色的,则它的两个子节点都是黑色的。
  5. 对于每个节点,从该节点到其所有后代叶子节点的简单路径上,均包含相同数目黑色节点

TreeSet 的内部节点通常包含一个键(key)、颜色信息左右子节点的引用以及父节点的引用(在某些实现中可能不包括父节点的引用)。

构造方法

 TreeSet<Integer> numbers = new TreeSet<>();

 常用方法

应用场景

  • 当需要保持元素的有序性且不允许重复时,TreeSet是一个很好的选择。
  • 常用于需要按照特定顺序处理元素的情况

 

 3.2.2.3、LinkedHashSet

它继承自 HashSet,因此具有哈希表的查找性能,同时又使用链表维护元素的插入顺序

会保持元素的插入顺序,即元素被添加到集合中的顺序就是它们在集合中的顺序。且保证唯一性

构造函数

  1. LinkedHashSet<String> linkedHashSet = new LinkedHashSet<>();
  2. ----------------------------------------------------------------
  3. #从现有的集合(如 List 或 Set)创建一个 LinkedHashSet
  4. Set<String> existingSet = new HashSet<>(Arrays.asList("A", "B", "C"));
  5. LinkedHashSet<String> linkedHashSet = new LinkedHashSet<>(existingSet);

 常用方法

  1. linkedHashSet.add("D");添加元素
  2. linkedHashSet.remove("B");删除元素
  3. linkedHashSet.contains("C");查询元素是否存在
  4. linkedHashSet.isEmpty()是否为空
  5. linkedHashSet.size();获取大小
  6. linkedHashSet.clear();清空
  7. String[] array = linkedHashSet.toArray(new String[0]);将 LinkedHashSet 中的元素转换为数组
  8. -------------------------------------------
  9. #比较两个 LinkedHashSet 是否相等
  10. LinkedHashSet<String> set1 = new LinkedHashSet<>(Arrays.asList("苹果", "香蕉", "橙子"));
  11. LinkedHashSet<String> set2 = new LinkedHashSet<>(Arrays.asList("苹果", "香蕉", "橙子"));
  12. boolean isEqual = set1.equals(set2); // 返回 true

3.3、Map

Map中的集合,元素是成对存在的。每个元素由键与值两部分组成,通过键可以找对所对应的值。

3.3.1、Hashmap

HashMap 是无序的,即不会记录插入的顺序。

HashMap基于数组和链表的结构,数组用于存储元素,链表用于解决哈希冲突

构造函数

HashMap<Integer, String> Sites = new HashMap<Integer, String>();

常用方法

  1. put(K key, V value): 将键(key)/值(value)映射存放到Map集合中。
  2. get(Object key): 返回指定键所映射的值,没有该key对应的值则返回 null。
  3. size(): 返回Map集合中数据数量。
  4. clear(): 清空Map集合。
  5. isEmpty(): 判断Map集合中是否有数据,如果没有则返回true,否则返回false
  6. remove(Object key): 删除Map集合中键为key的数据并返回其所对应value值。
  7. values(): 返回Map集合中所有value组成的以Collection数据类型格式数据。
  8. containsKey(Object key): 判断集合中是否包含指定键,包含返回 true,否则返回false
  9. containsValue(Object value): 判断集合中是否包含指定值,包含返回 true,否则返回false
  10. keySet(): 返回Map集合中所有key组成的Set集合。
  11. entrySet(): 将Map集合每个key-value转换为一个Entry对象并返回由所有的Entry对象组成的Set集合
  12. -------------------------------------
  13. 在Hash中可以直接使用以下方法遍历(所有键)KeySet
  14. HashMap<String,String> map = new HashMap<String,String>();
  15. for (String i : map.keySet())
  16. {
  17. //String 是mp中的键的对应类型 i 是对应的KeySet中的每一个键值  
  18. System.out.println( map.get(i)); 
  19. }
  20. //通过迭代器的方式遍历:
  21. Set<Map.Entry<String,String>> set=map.entrySet();
  22. Iterator<Map.Entry<String,String>> it=set.iterator();
  23. while(it.hasNext()){
  24. Map.Entry<String,String> e=it.next();
  25. System.out.println(e);
  26. }

3.3.2、Hashtable

Hashtable 的函数都是同步的,这意味着它是线程安全的。它的key、value都不可以为null。此外,Hashtable中的映射不是有序的

构造函数

 Hashtable<String,Integer> ht=new Hashtable()<>;

常用方法

  1. 1 void clear( )
  2. 将此哈希表清空,使其不包含任何键。
  3. 2 Object clone( )
  4. 创建此哈希表的浅表副本。
  5. 3 boolean contains(Object value)
  6. 测试此映射表中是否存在与指定值关联的键。
  7. 4 boolean containsKey(Object key)
  8. 测试指定对象是否为此哈希表中的键。
  9. 5 boolean containsValue(Object value)
  10. 如果此 Hashtable 将一个或多个键映射到此值,则返回 true
  11. 6 Enumeration elements( )
  12. 返回此哈希表中的值的枚举。
  13. 7 Object get(Object key)
  14. 返回指定键所映射到的值,如果此映射不包含此键的映射,则返回 null. 更确切地讲,如果此映射包含满足 (key.equals(k)) 的从键 k 到值 v 的映射,则此方法返回 v;否则,返回 null
  15. 8 boolean isEmpty( )
  16. 测试此哈希表是否没有键映射到值。
  17. 9 Enumeration keys( )
  18. 返回此哈希表中的键的枚举。
  19. 10 Object put(Object key, Object value)
  20. 将指定 key 映射到此哈希表中的指定 value。
  21. 11 void rehash( )
  22. 增加此哈希表的容量并在内部对其进行重组,以便更有效地容纳和访问其元素。
  23. 12 Object remove(Object key)
  24. 从哈希表中移除该键及其相应的值。
  25. 13 int size( )
  26. 返回此哈希表中的键的数量。
  27. 14 String toString( )
  28. 返回此 Hashtable 对象的字符串表示形式,其形式为 ASCII 字符 ", " (逗号加空格)分隔开的、括在括号中的一组条目。

 

3.4、总结

数据结构实现:ArrayList(可变数组)、LinkedList(双向列表)

高层次数据结构:Queue(队列)、Deque(双端队列)、Stack(栈)、HashSet(只存键的hash表)、Hashmap(普通的hash表)

有序且不重复的值的存储的数据结构:TreeSet(红黑树实现)、LinkedHashSet

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/繁依Fanyi0/article/detail/793495
推荐阅读
相关标签
  

闽ICP备14008679号