劍指Offer(10)有環鏈表 翻轉鏈表

劍指offer(10) 有環鏈表 反轉鏈表

題目:

給一個鏈表,若其中包含環,請找出該鏈表的環的入口結點,否則,輸出null。

思路:

快慢指針,當前一個指針和後一個指針相遇時,有環,提前結束則無.

然後將慢指針指向頭節點,兩個指針一起走,每次都走一步,相遇時即爲入口節點。

(以下證明學習自牛客卻顧所來徑的回答)

1、設置快慢指針,假如有環,他們最後一定相遇。

2、兩個指針分別從鏈表頭和相遇點繼續出發,每次走一步,最後一定相遇與環入口。

證明結論1:設置快慢指針fast和low,fast每次走兩步,low每次走一步。假如有環,兩者一定會相遇(因爲low一旦進環,可看作fast在後面追趕low的過程,每次兩者都接近一步,最後一定能追上)。

證明結論2:

設:

鏈表頭到環入口長度爲–a

環入口到相遇點長度爲–b

相遇點到環入口長度爲–c

img

則:相遇時

快指針路程=a+(b+c)k+b ,k>=1 其中b+c爲環的長度,k爲繞環的圈數(k>=1,即最少一圈,不能是0圈,不然和慢指針走的一樣長,矛盾)。

慢指針路程=a+b

快指針走的路程是慢指針的兩倍,所以:

(a+b)*2=a+(b+c)k+b

化簡可得:

a=(k-1)(b+c)+c 這個式子的意思是: 鏈表頭到環入口的距離=相遇點到環入口的距離+(k-1)圈環長度。其中k>=1,所以k-1>=0圈。所以兩個指針分別從鏈表頭和相遇點出發,最後一定相遇於環入口。

鏈接:https://www.nowcoder.com/questionTerminal/253d2c59ec3e4bc68da16833f79a38e4?f=discussion來源:牛客網

代碼:

public ListNode EntryNodeOfLoop(ListNode pHead)
    {
        ListNode fast=pHead;
        ListNode low=pHead;
        while(fast!=null&&fast.next!=null){
            fast=fast.next.next;
            low=low.next;
            if(fast==low)
                break;
            //找到相遇點
        }
        if(fast==null||fast.next==null)
            return null;
        low=pHead;
        //慢指針從頭開始
        while(fast!=low){
            fast=fast.next;
            low=low.next;
        }
        return low;
        //如果相遇返回環入口
    }

題目:

輸入一個鏈表,反轉鏈表後,輸出新鏈表的表頭。

思路:

方法1

建立一個棧,每次push進去節點,知道爲空,然後每次pop出來的節點的next指針指向下一個pop出來的節點,直到棧爲空。時間空間均爲O(n)

方法2

維護2個指針,遍歷的時候,直接將指針的指向逆序。時間O(n),空間O(1)。

方法3

遞歸,先遞歸到最後一個節點,然後逆向處理每個節點,直到遞歸至反轉前的第一個節點。

TIM圖片20190926155731.png

假如1-2-3-4

反轉後的是 4-3-2-1

修改了指向後,原鏈表指向還存在,需要刪除,所以有head->next = NULL; 依照這樣的思路一直遞歸到1,返回之前記錄的節點

代碼:

/**
     * 建立一個棧,每次push進去節點,知道爲空,
     * 然後每次pop出來的節點的next指針指向下一個pop出來的節點,直到棧爲空。時間空間均爲O(n)
     */
    public ListNode ReverseList(ListNode head)
    {
        if (head == null)
        {
            return null;
        }
        if (head.next == null)
        {
            return head;
        }
        ListNode p = head;
        Stack<ListNode> stack = new Stack();
        while (p.next != null)
        {
            stack.push(p);
            p = p.next;
        }
        ListNode newHead = p;
        while (!stack.empty())
        {
            p.next = stack.pop();
            p = p.next;
        }
        p.next = null;
        //最後一個指向null
        return newHead;
    }

    /**
     * 維護2個指針,遍歷的時候,
     * 直接將指針的指向逆序。時間O(n),空間O(1)。
     */
    public ListNode ReverseList1(ListNode head)
    {
        if (head == null)
        {
            return null;
        }
        if (head.next == null)
        {
            return head;
        }
        ListNode pre = null;
        ListNode next = null;
        while (head != null)
        {
            next = head.next;
            head.next = pre;
            pre = head;
            head = next;
        }
        return pre;
    }

    /**
     * 遞歸方法
     * 處理當前節點前,處理當前節點的下一個節點
     * 遞歸到最後一個節點開始處理
     */
    public static ListNode ReverseList2(ListNode pHead)
    {
        //如果鏈表爲空或者鏈表中只有一個元素
        if(pHead==null||pHead.next==null) return pHead;

        //先反轉後面的鏈表,走到鏈表的末端結點
        ListNode pReverseNode=ReverseList2(pHead.next);

        //再將當前節點設置爲後面節點的後續節點
        pHead.next.next=pHead;
        pHead.next=null;

        return pReverseNode;
    }
    public static void main(String[] args)
    {
        ListNode node1 = new ListNode(1);
        ListNode node2 = new ListNode(2);
        ListNode node3 = new ListNode(3);
        ListNode node4 = new ListNode(4);
        ListNode node5 = new ListNode(5);
        ListNode node6 = new ListNode(6);
        ListNode node7 = new ListNode(7);

        node1.next = node2;
        node2.next = node3;
        node3.next = node4;
        node4.next = node5;
        node5.next = node6;
        node6.next = node7;

        ListNode old = node1;
        while (old != null)
        {
            System.out.print(" " + old.val);
            old = old.next;
        }
        System.out.println();
//        deleteDuplication(node1);
        ListNode newNode = ReverseList2(node1);
        while (newNode != null)
        {
            System.out.print(" " + newNode.val);
            newNode = newNode.next;
        }
    }

ion(node1);
ListNode newNode = ReverseList2(node1);
while (newNode != null)
{
System.out.print(" " + newNode.val);
newNode = newNode.next;
}
}




發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章