二叉树遍历+链表补充题

1、
题目:给定两个可能有环也可能无环的单链表,头节点head1,head2,请实现一个函数,若2个链表相交,请返回相交的第一个节点,若不相交,返回null

package learn;

public class Test {

        public static class Node{
            public int value;
            public Node next;
            public Node(int value){//构造方法
    
                this.value=value;
            }
        }
    
        public static Node getIntersectionNode(Node head1,Node head2) {//找两链表相交的第一个节点
            if(head1==null || head2==null){
                return null;
            }
            Node loop1=getLoopNode(head1);
            Node loop2=getLoopNode(head2);
    
            if(loop1==null && loop1==null){//两者都无环 从相交节点到尾一定都共有
                return noLoop(head1,head2);
            }else if(loop1!=null &&loop2!=null){
                return bothLoop(head1,head2,loop1,loop2);
            }else {
                return null;
            }
        }
    
        public static Node getLoopNode(Node head) {
    
            if(head.next==null || head.next.next==null){//别忘了考虑边界情况 只有一个节点或者两个节点 不可能构成环
                return null;
            }
            Node s=head.next;
            Node f=head.next.next;
            while (s!=f){//有环一定会相遇
                if(f.next==null || f.next.next==null){//别忘了考虑无环情况
                    return null;//无环一定能走到尾且快指针先到尾 有环是无法走到尾的
                }
                s=s.next;
                f=f.next.next;
            }
    
            f=head;
    
            while (s!=f){
                f=f.next;
                s=s.next;
            }
            return s;
        }
    
        public static Node noLoop(Node head1,Node head2) {//都为无环链表
            Node n1=head1;
            Node n2=head2;
            int len1=0,len2=0;
            while (n1.next!=null){//n1指向表一末尾时退出
                len1++;
                n1=n1.next;
            }
    
            while (n2.next!=null){//n1指向表一末尾时退出
                len2++;
                n2=n2.next;
            }
    
            if(n1!=n2){
                return null;
            }
    
            if(len1>len2){//n1指向长链表 n2指向短链表
                n1=head1;
                n2=head2;
            }else {
                n1=head2;
                n2=head1;
            }
    
            int n=Math.abs(len1-len2);
            while (n!=0){
                n--;
                n1=n1.next;
            }
    
            while (n1!=n2){
                n1=n1.next;
                n2=n2.next;
            }
            return n2;
        }

    public static Node bothLoop(Node head1,Node head2,Node loop1,Node loop2) {
            Node n1=head1,n2=head2;
            int n=0;
            if(loop1==loop2){//将入环节点看为终止节点 将问题转化为无环节点交点问题
                while (n1!=loop1){
                    n++;
                    n1=n1.next;
                }
                
                while (n2!=loop2){
                    n--;
                    n2=n2.next;
                }
                
                n1=n>0?head1:head2;
                n2=(n1==head1)?head2:head1;
                
                n=Math.abs(n);
                while (n!=0){
                    n--;
                    n1=n1.next;
                }
                
                while (n1!=n2){
                    n1=n1.next;
                    n2=n2.next;
                }
                return n1;
            }else {
                n1=loop1.next;
                
                while (n1!=loop1){
                    if(n1==loop2){
                        return loop1;
                    }
                    n1=n1.next;
                }
                return null;
            }
    }
}

2、二叉树遍历:
(1)递归:

package learn;

public class Test {

        public static class Node{
            public int value;
            public Node left;
            public Node right;
            public Node(int value){//构造方法

                this.value=value;
            }
        }
        
        public static void preOrderTraverse(Node head){//根左右
            if(head==null){
                return;
            }else {
                System.out.println(head.value);
                preOrderTraverse(head.left);
                preOrderTraverse(head.right);
            }
        }

        public static void inOrderTraverse(Node head){//左根右
            if(head==null){
                return;
            }else {
                preOrderTraverse(head.left);
                System.out.println(head.value);
                preOrderTraverse(head.right);
            }
        }
            
            
        public static void posOrderTraverse(Node head){//左右根
            if(head==null){
                return;
            }else {
                preOrderTraverse(head.left);
                preOrderTraverse(head.right);
                System.out.println(head.value);
            }
        }
}

(2)非递归:

package learn;

import java.util.Stack;

public class Test {

        public static class Node{
            public int value;
            public Node left;
            public Node right;
            public Node(int value){//构造方法

                this.value=value;
            }
        }

        public static void preOrderTraverse(Node head){//根左右
            if(head==null){
                return;
            }else {
                Stack<Node> s=new Stack<Node>();
                s.push(head);
                if(!s.empty()){
                    head=s.pop();
                    System.out.print(head.value+" ");//根
                    if(head.right!=null){//入栈:右左 出栈:左右
                        s.push(head.right);
                    }
                    if(head.left!=null){
                        s.push(head.left);
                    }
                }
            }
        }

        public static void inOrderTraverse(Node head){//左根右
            if(head==null){
                return;
            }else {
                Stack<Node> s=new Stack<Node>();
                while (!s.empty() || head!=null){//head 每棵子树的根
                    if(head!=null){
                        s.push(head);
                        head=head.left;
                    }else{
                    head=s.pop();
                    System.out.print(head.value+" ");
                    head=head.right;
                    }
                }
            }
        }


        public static void posOrderTraverse(Node head){//左右根
            if(head==null){
                return;
            }else {
                Stack<Node> s1=new Stack<Node>();
                Stack<Node> s2=new Stack<Node>();
                s1.push(head);
                while (!s1.empty()){
                    head=s1.pop();
                    s2.push(head);
                    if(head.left!=null){
                        s1.push(head.left);
                    }
                    
                    if(head.right!=null){
                        s1.push(head.right);
                    }
                }
                while (!s2.empty()){
                    head=s2.pop();
                    System.out.println(head.value+" ");
                }
            }
        }
}

二叉树的深度优先遍历即它的先序遍历

宽度优先遍历:队列

        public static void widthTraverse(Node head){
            if(head==null){
                return;
            }else {
                Queue<Node> q=new LinkedList<Node>();//双向链表实现队列
                q.add(head);
                while (!q.isEmpty()) {
                    head = q.poll();
                    System.out.println(head.value + " ");
                    if (head.left != null) {
                        q.add(head.left);
                    }
                    if (head.right != null) {
                        q.add(head.right);
                    }
                }
            }
        }

3、
(1)求二叉树中所有层中节点数的最大值(利用宽度优先遍历)

package learn;

import java.util.HashMap;
import java.util.LinkedList;
import java.util.Queue;

public class Test {

        public static class Node{
            public int value;
            public Node left;
            public Node right;
            public Node(int value){//构造方法

                this.value=value;
            }
        }

        public static int widthTraverse(Node head) {
            if (head == null) {
                return 0;
            } else {
                Queue<Node> q = new LinkedList<Node>();//双向链表实现队列
                HashMap<Node, Integer> h = new HashMap<Node, Integer>();
                int level = 1;//当前层
                int nodeLevel = 1;//节点所在层
                int levelNodesNum = 0;//当前层节点数统计
                int max = Integer.MIN_VALUE;
                h.put(head, nodeLevel);
                q.add(head);
                while (!q.isEmpty()) {
                    head = q.poll();
                    if (h.get(head) == level) {
                        levelNodesNum++;
                    } else {//现在观测的节点不在当前统计的层了
                        max = Math.max(max, levelNodesNum);//结算当前节点的上一层节点数和最大值谁大谁小
                        level++;//结算后进入下一层(即当前节点所在层)
                        levelNodesNum = 1;//当前节点为此层记录的第一个节点
                    }
                    if (head.left != null) {
                        q.add(head.left);
                        h.put(head.left, level + 1);//head的子女在它的下一层
                    }
                    if (head.right != null) {
                        q.add(head.right);
                        h.put(head.right, level + 1);
                    }
                }
                max = Math.max(max, levelNodesNum);
                return max;
            }
        }
}

(2)二叉树最大宽度(leetcode 662)
同样利用宽度优先遍历,与求所有层最大节点个数不同的是,比如第三层的节点为[v1,v2,null,v4]时,最多节点个数是3,而最大宽度是4。可以使用双端队列的方式,最右节点下标-最左节点下标+1 即为当前宽度。
两个hashmap 一个存放节点对应的下标 一个存放节点对应的层。
每次到下一层的时候,结算上一层。上一层刚结束时,队列中节点是只有当前层的,当前层的下一层节点还未入队。

package learn;

import java.util.Deque;
import java.util.HashMap;
import java.util.LinkedList;

public class Test {
    public static class Node {
        public int value;
        public Node left;
        public Node right;

        public Node(int value) {//构造方法
            this.value = value;
        }
    }

    public static int widthTraverse(Node head) {
        if (head == null) {
            return 0;
        } else {
            Deque<Node> dq = new LinkedList<Node>();//双端队列
            HashMap<Node, Integer> h1 = new HashMap<Node, Integer>();//存放当前节点的下标
            HashMap<Node, Integer> h2 = new HashMap<Node, Integer>();//存放当前节点所在层
            dq.add(head);

            int nowNodeLevel=1;
            int nowMax=1;//head!=null 说明至少一个节点 宽度至少为1

            h1.put(head,0);
            h2.put(head,nowNodeLevel);
            while (!dq.isEmpty()){
                Node cur=dq.peek();
                int i=h1.get(cur);//当前节点的下标

                if(h2.get(cur)!=nowNodeLevel){//上一层刚结束时,队列中节点是只有当前层的,当前层的下一层节点还未入队
                    nowMax=Math.max(h1.get(dq.getLast())-h1.get(dq.getFirst())+1,nowMax);

                    nowNodeLevel++;//进入当前层
                }

                dq.poll();
                if(cur.left!=null){
                    h1.put(cur.left,2*i+1);
                    h2.put(cur.left,nowNodeLevel+1);
                    dq.add(cur.left);
                }
                if(cur.right!=null){
                    h1.put(cur.right,2*i+2);
                    h2.put(cur.right,nowNodeLevel+1);
                    dq.add(cur.right);
                }
            }
            return nowMax;
        }
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值