剑指offer(54-59)

第54题

题目描述:给一个链表,若其中包含环,请找出该链表的环的入口结点,否则,输出null。

思路分析:
1.首先肯定想到的是将每一个访问到的结点记录下来(比如HashSet),然后对每一个遇到的结点进行判断,以确定新的结点是否已经在之前出现过。但是这种方式当我在运行的时候会超时。

2.快慢指针的方式。如下:
在这里插入图片描述

代码如下:

public class Solution {
    public ListNode EntryNodeOfLoop(ListNode pHead){
        //设置快慢指针
        ListNode fast = pHead;
        ListNode slow = pHead;
        
        //找到相遇的位置
        while(fast!=null&&fast.next!=null){
            fast = fast.next.next; //一次两步
            slow = slow.next;
            if(fast == slow){
                break;
            }
        }
        
        if(fast==null||fast.next==null)
            return null;
        //找到入口
        slow=pHead;
        while(fast!=slow){
            fast=fast.next;   //一次一步
            slow=slow.next;
        }
        return slow;
    }
}

第55题

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

思路分析: 首先基本的知识点是考查链表结点的删除,当删除链表结点的时候,我们要知道被删除结点前面的一个结点的位置。故本题至少要设置两个指针,一个指针用于指示当前要删除结点的前一个结点(本题中删除的结点可能是多个,那么就至少需要一个指针指向这个多个结点中第一个结点的前一个结点);此外还需要一个指针用于确实删除的范围。

代码如下:

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 = pHead; //用于指示范围
        
        while(last!=null){
            if(last.next!=null&&last.val == last.next.val){
                //记录当前的重复值
                int value = last.val;
                //找到最后一个重复的结点(循环结束后pre和last中间的结点就是要删除的结点)
                while(last!=null&&last.val == value){
                    last = last.next;
                }
                //删除结点
                pre.next = last;
                
            }else{
                pre = pre.next;
                last = last.next;
            }
        }
        return Head.next;
    }
}

第56题

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

思路分析: 如下图所示
在这里插入图片描述
分析二叉树的下一个节点,一共有以下情况:
1.二叉树为空,则返回空;
2.节点右孩子存在,则设置一个指针从该节点的右孩子出发,一直沿着指向左子结点的指针找到的叶子节点即为下一个节点;
3.节点不是根节点。如果该节点是其父节点的左孩子,则返回父节点;否则继续向上遍历其父节点的父节点,重复之前的判断,返回结果。

代码如下:

public class Solution {
    public TreeLinkNode GetNext(TreeLinkNode pNode)
    {
        //pNode为空,或者pNode没有右结点和父节点(情况1)
        if(pNode==null || (pNode.right==null&&pNode.next==null)){
            return null;
        }
        //右子树不为空(右子树中一直找到最后一个左孩子<情况2>)
        if(pNode.right!=null){
            pNode = pNode.right;
            while(pNode.left!=null){
                pNode = pNode.left;
            }
            return pNode;
        }
        //第三种情况
        while(pNode.next != null){
            //如果是左子树
            if(pNode == pNode.next.left)
                return pNode.next;
            pNode = pNode.next;
         }
         return null;
    }
}

第57题

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

思路分析: 实际上是个递归过程。
代码如下:

public class Solution {
    boolean isSymmetrical(TreeNode pRoot)
    {
        //使用递归
        if(pRoot == null){
            return true;
        }
        return isSymmetrical(pRoot.left,pRoot.right);
    }
    //对左右结点进行判断
    private boolean isSymmetrical(TreeNode left,TreeNode right){
        //两个都为Null,符合
        if(left==null && right==null){
            return true;
        }
        //假如有一个为Null,不符合
        if(left==null || right==null){
            return false;
        }
        //值相等,再对子树进行判断(注意递归传入参数的位置)
        if(left.val == right.val){
            return isSymmetrical(left.left,right.right) && isSymmetrical(left.right,right.left);
        }
        return false;
    }
}

第58题

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

思路分析: 本题类似二叉树的层次遍历,思想上是类似的,只是细节的地方有所改变。通过分析可以知道,本题需要栈协助完成。奇数层(从1开始)按照正常顺序入栈,即对一个结点来说先入左结点、再入右结点;偶数层时,对每个结点先入右结点再入左结点。同时明显地我们需要两个栈,一个栈在出栈,另一个栈进行入栈,交替地运行。

代码如下:

public class Solution {
    public ArrayList<ArrayList<Integer> > Print(TreeNode pRoot) {
        
        ArrayList<ArrayList<Integer>> list = new ArrayList<ArrayList<Integer>>();
        
        if(pRoot == null){
            return list;
        }
        
        //s1存放奇数结点
        Stack<TreeNode> s1 = new Stack<TreeNode>();
        s1.push(pRoot);
        //s2存放偶数结点
        Stack<TreeNode> s2 = new Stack<TreeNode>();
        
        //记录层数
        int layer = 1;
        
        //当栈不为空时
        while(!s1.empty()||!s2.empty()){
            //奇数
            if(layer%2 == 1){
                ArrayList<Integer> temp = new ArrayList<Integer>();
                while(!s1.empty()){
                    TreeNode node = s1.pop();
                    if(node.left!=null){
                        s2.push(node.left);
                    }
                    if(node.right!=null){
                        s2.push(node.right);
                    }
                    temp.add(node.val);
                }
                
                if(!temp.isEmpty()){
                    list.add(temp);
                    layer++;
                }
                
            }else{
                //偶数
                ArrayList<Integer> temp = new ArrayList<Integer>();
                 while(!s2.empty()){
                    TreeNode node = s2.pop();
                    if(node.right!=null){
                        s1.push(node.right);
                    }
                    if(node.left!=null){
                        s1.push(node.left);
                    }
                    temp.add(node.val);
                }
                if(!temp.isEmpty()){
                    list.add(temp);
                    layer++;
                }
            }
        }       
        return list;
    }
}

第59题

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

思路描述: 本题和上一题的思路类似,实际上就是二叉树层次遍历,不过需要小的修改。

代码如下:

public class Solution {
    ArrayList<ArrayList<Integer> > Print(TreeNode pRoot) {
        //二叉树的层次遍历
        ArrayList<ArrayList<Integer>> list = new ArrayList<ArrayList<Integer>>();
        if(pRoot == null){
            return list;
        }
        
        //定义队列
        Queue<TreeNode> q1 = new ArrayDeque<TreeNode>();
        Queue<TreeNode> q2 = new ArrayDeque<TreeNode>();
        q1.add(pRoot);
        
        while(!q1.isEmpty() || !q2.isEmpty()){
            if(!q1.isEmpty()){
                ArrayList<Integer> temp = new ArrayList<Integer>();
                while(!q1.isEmpty()){
                    TreeNode node = q1.poll();
                    if(node.left!=null){
                        q2.add(node.left);
                    }
                    if(node.right!=null){
                        q2.add(node.right);
                    }
                    temp.add(node.val);
                }
                if(!temp.isEmpty()){
                    list.add(temp);
                }
                
            }else{
                
                ArrayList<Integer> temp = new ArrayList<Integer>();
                while(!q2.isEmpty()){
                    TreeNode node = q2.poll();
                    if(node.left!=null){
                        q1.add(node.left);
                    }
                    if(node.right!=null){
                        q1.add(node.right);
                    }
                    temp.add(node.val);
                }
                if(!temp.isEmpty()){
                    list.add(temp);
                }
            }
        }  
        return list;
    }   
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章