劍指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;
    }   
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章