剑指Offer系列之题56~题60

56.删除链表中重复的结点 🔺

在一个排序的链表中,存在重复的结点,请删除该链表中重复的结点,重复的结点不保留,返回链表头指针。 例如,链表1->2->3->3->4->4->5 处理后为 1->2->5

添加头结点,作为辅助,便于剔除第一个和第二节点就相等的情况;

递归。都需要考虑开头就出现两节点相等的情况。


1.添加头结点:

/*
 public class ListNode {
    int val;
    ListNode next = null;

    ListNode(int val) {
        this.val = val;
    }
}
*/
public class Solution {
    public ListNode deleteDuplication(ListNode pHead)
    {
        if(pHead==null || pHead.next==null){
            return pHead;
        }
        //可能存在多个相同
        ListNode head=new ListNode(0);//头结点
        head.next=pHead;

        ListNode pre=head;
        ListNode last=head.next;//从第一个结点开始

        while(last!=null){
            if(last.next!=null && last.val==last.next.val){
                //循环直到last.next为空或者找到不重复结点
                while(last.next!=null && last.val==last.next.val)
                    last=last.next;
                pre.next=last.next;//last.next为空则直接链接null,否则链接不重复结点
                last=last.next;
            }else{
                pre=pre.next;//不等时,前结点后移
                last=last.next;
            }
        }

        return head.next;
    }
}

2.递归:

/*
 public class ListNode {
    int val;
    ListNode next = null;

    ListNode(int val) {
        this.val = val;
    }
}
*/
public class Solution {
    public ListNode deleteDuplication(ListNode pHead)
    {
        if(pHead==null || pHead.next==null){
            return pHead;
        }

        //两个循环,用来应付“1-1-2-2-3-3-4-5…”格式的连续重复结点
       while(pHead != null && pHead.next != null && pHead.val == pHead.next.val){
           while(pHead != null && pHead.next != null && pHead.val == pHead.next.val){
               pHead = pHead.next;
           }//找到当前与下一节点不等的结点
           pHead = pHead.next;//将该节点右移
       }
       if(pHead!=null ){
           pHead.next = deleteDuplication(pHead.next);
       }
       return pHead;
    }
}

57.二叉树的下一结点

给定一个二叉树和其中的一个结点,请找出中序遍历顺序的下一个结点并且返回。注意,树中的结点不仅包含左右子结点,同时包含指向父结点的指针。

判断该节点右子树是否为空,非空则返回右子树的最左子节点;

判断父节点是否空,非空则判断该节点是父节点的左或右子树,左子树则返回父节点,右子树则从父结点开始找到是父节点左子节点的结点,返回该节点的父节点


1.:

/*
public class TreeLinkNode {
    int val;
    TreeLinkNode left = null;
    TreeLinkNode right = null;
    TreeLinkNode next = null;

    TreeLinkNode(int val) {
        this.val = val;
    }
}
*/
public class Solution {
    public TreeLinkNode GetNext(TreeLinkNode pNode)
    {
        //中序:左 根 右
        //不仅包含左右子结点,同时包含指向父结点的指针。
        if(pNode==null)
            return null;

        TreeLinkNode next=null;
        if(pNode.right!=null){//找到右子树的最左子节点
            TreeLinkNode temp=pNode.right;
            while(temp!=null){
                if(temp.left==null){
                    next=temp;
                    break;
                }else{
                    temp=temp.left;
                }
            }
        }else if(pNode.next!=null){//父节点非空
            //判断该节点是父节点的左或右子树
            TreeLinkNode father=pNode.next;//找到其父节点
            if(father.left==pNode)
                return father;//如果是父节点的左子树,则返回父节点
            //若是父节点的右子树,则沿着其父节点向上找到 是它父节点左子节点的结点,则其父节点是下个结点
            if(father.right==pNode){
                while(father.next!=null){
                    if(father==father.next.left){
                        next=father.next;;
                        break;
                    }
                    father=father.next;
                }
            }
        }
        return next;
    }
}

58.对称的二叉树

请实现一个函数,用来判断一颗二叉树是不是对称的。注意,如果一个二叉树同此二叉树的镜像是同样的,定义其为对称的。

递归:前序(根左右)遍历和根右左遍历序列相等时,二叉树对称;

非递归:利用栈或队列成对存储元素,成对取出比较。


1.递归:

/*
public class TreeNode {
    int val = 0;
    TreeNode left = null;
    TreeNode right = null;

    public TreeNode(int val) {
        this.val = val;

    }

}
*/
public class Solution {
    boolean isSymmetrical(TreeNode pRoot)
    {
        //前序遍历和 根右左遍历序列相等则对称
        return helper(pRoot,pRoot);
    }
    //遍历的节点  root1前序遍历  root2根左右顺序遍历
    boolean helper(TreeNode root1,TreeNode root2){
        if(root1==null && root2==null)//两节点都为空则true
            return true;
        if(root1==null || root2==null)//两节点只有一个为空,false
            return false;
        if(root1.val!=root2.val)//两节点值不等,false
            return false;
        return helper(root1.left,root2.right) && helper(root1.right,root2.left);
    }
}

2.非递归:

栈如下;队列同理,代码相似。不过前者是DFS,后者是BFS

import java.util.Stack;
public class Solution {
    boolean isSymmetrical(TreeNode pRoot)
    {
        if(pRoot==null)
            return true;
        //栈成对 存储 取出节点
        Stack<TreeNode> stack=new Stack<>();
        stack.push(pRoot.left);
        stack.push(pRoot.right);
        while(!stack.empty()){
            TreeNode right=stack.pop();
            TreeNode left=stack.pop();

            if(left ==null && right==null)
                continue;
            if(left ==null || right==null)
                return false;
            if(left.val!=right.val)
                return false;
            //入四个,下次出两个,会先进行到叶节点,然后再向上返回遍历其他节点。->深度优先
            stack.push(left.left);
            stack.push(right.right);
            stack.push(left.right);
            stack.push(right.left);
        }
        return true;
    }
}

59.按之字形顺序打印二叉树

请实现一个函数按照之字形打印二叉树,即第一行按照从左到右的顺序打印,第二层按照从右至左的顺序打印,第三行按照从左到右的顺序打印,其他行以此类推。

辅助栈存储奇数偶数层的结点,然后输出。因为从左到右,从右到左,栈符合该特点;

或者使用双端队列


1. 辅助栈:

import java.util.ArrayList;

/*
public class TreeNode {
    int val = 0;
    TreeNode left = null;
    TreeNode right = null;

    public TreeNode(int val) {
        this.val = val;

    }

}
*/
import java.util.Stack;
public class Solution {
    public ArrayList<ArrayList<Integer> > Print(TreeNode pRoot) {
        ArrayList<ArrayList<Integer>> resList=new ArrayList<>();
        if(pRoot==null)
            return resList;
        int depth=0;//层数,当奇数从左到右,偶数从右到左
        Stack<TreeNode> stack1=new Stack<>();//奇数层栈
        Stack<TreeNode> stack2=new Stack<>();//偶数层栈
        stack1.push(pRoot);
        TreeNode temp=null;
        while(!stack1.empty() || !stack2.empty()){
            depth++;//当前层
            ArrayList<Integer> res=new ArrayList<>();
            if(depth%2!=0){//奇数层
                while(!stack1.empty()){
                    temp=stack1.pop();
                    res.add(temp.val);
                    //下一层从左到右入
                    if(temp.left!=null)
                        stack2.push(temp.left);
                    if(temp.right!=null)
                        stack2.push(temp.right);
                }
            }else{//偶数层
                while(!stack2.empty()){
                    temp=stack2.pop();
                    res.add(temp.val);
                    //下一层从右到左入
                    if(temp.right!=null)
                        stack1.push(temp.right);
                    if(temp.left!=null)
                        stack1.push(temp.left);
                }
            }
            resList.add(res);
        }
        return resList;
    }
}

60.把二叉树打印成多行

从上到下按层打印二叉树,同一层结点从左至右输出。每一层输出一行。

层次遍历,利用辅助队列


1.队列;

import java.util.ArrayList;
import java.util.Queue;
import java.util.LinkedList;

/*
public class TreeNode {
    int val = 0;
    TreeNode left = null;
    TreeNode right = null;

    public TreeNode(int val) {
        this.val = val;
    }
}
*/
public class Solution {
    ArrayList<ArrayList<Integer> > Print(TreeNode pRoot) {
        //层次遍历
        ArrayList<ArrayList<Integer>>  resList=new ArrayList<>();
        if(pRoot==null)
            return resList;
        Queue<TreeNode> queue=new LinkedList<>();
        int width=0;//宽度,当前层结点个数
        int count=0;//当前层已遍历结点数
        TreeNode temp=null;//存储遍历的结点
        queue.offer(pRoot);
        while(!queue.isEmpty()){
            width=queue.size();
            ArrayList<Integer> res=new ArrayList<>();
            while(count<width){//遍历当前层
                temp=queue.poll();
                count++;
                res.add(temp.val);
                if(temp.left!=null)
                    queue.offer(temp.left);
                if(temp.right!=null)
                    queue.offer(temp.right);
            }
            count=0;
            resList.add(res);
        }
        return resList;
    }
}

2.递归:

public class Solution {
    ArrayList<ArrayList<Integer> > Print(TreeNode pRoot) {
        //层次遍历
        ArrayList<ArrayList<Integer>>  resList=new ArrayList<>();
        helper(pRoot,1,resList);//结点,结点所在层数,结果列表
        return resList;
    }
    public void helper(TreeNode root,int depth,ArrayList<ArrayList<Integer>> resList){
        if(root==null)//结点空则返回
            return;
        if(depth>resList.size())//若深度大于列表大小,说明该结点所在行还未记录
            resList.add(new ArrayList<Integer>());//添加一行
        resList.get(depth-1).add(root.val);//将当前节点的值添加到列表内的最后一行

        helper(root.left,depth+1,resList);//左右子树均在下一行进行遍历
        helper(root.right,depth+1,resList);
    }

}

如有错误,欢迎指正

posted @ 2020-04-16 13:02  雨落成尘  阅读(172)  评论(0编辑  收藏  举报