算法筆記:鏈表

//leetcode中還有花樣鏈表題娱局,這里幾個(gè)例子闷袒,冰山一角

  1. 求單鏈表中結(jié)點(diǎn)的個(gè)數(shù)----時(shí)間復(fù)雜度O(n)
    這是最最基本的了湿硝,應(yīng)該能夠迅速寫出正確的代碼,注意檢查鏈表是否為空贝乎。參考代碼如下:
    public static int getListLength(Node head) {
        // 注意頭結(jié)點(diǎn)為空情況
        if (head == null) {
            return 0;
        }

        int len = 0;
        Node cur = head;
        while (cur != null) {
            len++;
            cur = cur.next;
        }
        return len;
    }
  1. 將單鏈表反轉(zhuǎn)----時(shí)間復(fù)雜度O(n)(也可以先inplace的翻轉(zhuǎn),再遍歷叽粹,空間復(fù)雜度降到O(1))
  2. 從頭到尾遍歷原鏈表览效,每遍歷一個(gè)結(jié)點(diǎn),將其摘下放在新鏈表的最前端虫几。
  3. 如果鏈表為空或只有一個(gè)節(jié)點(diǎn)朽肥,無需反轉(zhuǎn),直接返回原鏈表表頭持钉。
    注意鏈表為空和只有一個(gè)結(jié)點(diǎn)的情況。參考代碼如下:
public static Node reverseList(Node head) {
        if (head == null || head.next == null) {
            return head;
        }

        Node reHead = null;         // 反轉(zhuǎn)后新鏈表最前面的node
        Node cur = head;

        while (cur != null) {
            Node preCur = cur;      // 用preCur保存住對(duì)要處理節(jié)點(diǎn)的引用
            cur = cur.next;             // cur更新到下一個(gè)節(jié)點(diǎn)
            preCur.next = reHead;   // 更新當(dāng)前節(jié)點(diǎn)的next引用篱昔,當(dāng)前.next指向 翻轉(zhuǎn)后鏈表最前面的node ==>當(dāng)前節(jié)點(diǎn)成為翻轉(zhuǎn)后鏈表最前面的node
            reHead = preCur;            // reHead更新
        }
        return reHead;
    }
  1. leetcode例題

206. Reverse LinkedList

沒做過一上來感覺不太好想每强,有個(gè)視頻,看到一半恍然大悟:https://www.youtube.com/watch?v=sYcOK51hl-A
這類題都開始要求用iteration寫一次再用recursive寫一個(gè)

 //假設(shè)1->2->3->4,先從head=1開始州刽,要翻轉(zhuǎn)空执,最后一個(gè)會(huì)變成head,所以head一步一步向后挪穗椅,每一步也一起翻轉(zhuǎn)指向
public class Solution {
            public ListNode reverseList(ListNode head) {
                ListNode prev = null;
                while(head!=null){
                    ListNode nextHead = head.next;
                    head.next = prev;
                    prev=head;
                    //這里得到的prev即下一個(gè)head前面的數(shù)辨绊,也就是下一個(gè)head要指向的數(shù),當(dāng)head=最后一個(gè)node(tail)時(shí)匹表,prev=tail门坷,循環(huán)結(jié)束
                    head = nextHead;
                } 
                return prev;
            }
            //recursive
            public ListNode reverseList(ListNode head) {
                return reverseRecursive(head,null);
            }
            public ListNode reverseRecursive(ListNode head,ListNode prev){
                if(head==null) return prev;
                ListNode nextHead = head.next;
                head.next=prev;
                //下面?zhèn)鲄⑵鋵?shí)就相當(dāng)于這兩句:prev=head;head = nextHead;
                return reverseRecursive(nextHead,head);
            }
        }

92. Reverse Linked List II

For example:
Given 1->2->3->4->5->NULL, m = 2 and n = 4,
return 1->4->3->2->5->NULL.

根據(jù)題中的例子宣鄙,第二個(gè)for循環(huán)開始
loop1:
1 --> 2 --> 3 --> 4 --> 5 --> NULL
p     c     n
cur.next = next.next;
2 --> 4
next.next = prev.next;
3 --> 2
prev.next = next;
1 --> 3
==> 1 --> 3 --> 2 --> 4 --> 5 --> NULL
    p          c      n
loop2:
cur.next = next.next;
2 --> 5
next.next = prev.next;
4 --> 3
prev.next = next;
1 --> 4
==> 1 --> 4 --> 3 --> 2 --> 5 --> NULL
public ListNode reverseBetween(ListNode head, int m, int n) {
            if(m == n) return head;
            ListNode dummy = new ListNode(0);
            dummy.next = head;
            ListNode prev = dummy;
            ListNode cur = head;
            //在reverse之前的部分平移
            for(int i = 0; i < m - 1; i++){
                prev = prev.next;
                cur = cur.next;
            }
            for(int i = 0; i < n - m; i++){
                ListNode next = cur.next;
                cur.next = next.next;
                next.next = prev.next;
                prev.next = next;
            }
            return dummy.next;
        }
  1. 查找單鏈表中的倒數(shù)第K個(gè)結(jié)點(diǎn)(k > 0)----時(shí)間復(fù)雜度O(n)
  2. 最普遍的方法是,先統(tǒng)計(jì)單鏈表中結(jié)點(diǎn)的個(gè)數(shù)默蚌,然后再找到第(n-k)個(gè)結(jié)點(diǎn)冻晤。注意鏈表為空,k為0绸吸,k為1鼻弧,k大于鏈表中節(jié)點(diǎn)個(gè)數(shù)時(shí)這三種情況情況。代碼不寫了锦茁。
  3. 另一個(gè)思路主要就是使用兩個(gè)指針攘轩,先讓前面的指針走到正向第k個(gè)結(jié)點(diǎn),這樣前后兩個(gè)指針的距離差是k-1码俩,之后前后兩個(gè)指針一起向前走度帮,前面的指針走到最后一個(gè)結(jié)點(diǎn)時(shí),后面指針?biāo)附Y(jié)點(diǎn)就是倒數(shù)第k個(gè)結(jié)點(diǎn)握玛。

19. Remove Nth Node From End of List

walker and runner, init walker,runner both as dummy, move runner n steps, so that the gap between runner and walker =n, then move runner and walker together, when runner get to the end of List, walker is before the nth from the end node, walker.next=walke.next.next够傍, skip original walker.next

public ListNode removeNthFromEnd(ListNode head, int n) {
            ListNode dummy = new ListNode(0);
            dummy.next = head;
            ListNode walker = dummy;
            ListNode runner = dummy;
            // after for loop, gap between runner and walker =n
            for(int i = 1; i <= n; i++){
                runner = runner.next;
            }
            while(runner.next!=null){
                runner = runner.next;
                walker = walker.next;
            }
            walker.next=walker.next.next;//skip nth node
            return dummy.next;
        }
  1. 查找單鏈表的中間結(jié)點(diǎn)----時(shí)間復(fù)雜度O(n)
    此題可應(yīng)用于上一題類似的思想。也是設(shè)置兩個(gè)指針挠铲,只不過這里是冕屯,兩個(gè)指針同時(shí)向前走,walker one step each time拂苹,runner two steps each time安聘,runner get to the end, walker==mid,即第(n/2+1)個(gè)結(jié)點(diǎn)瓢棒。還是分三種情況:鏈表結(jié)點(diǎn)個(gè)數(shù)為1和2的情況和其他浴韭。
public static Node getMiddleNode(Node head) {
        if (head == null || head.next == null) {
            return head;
        }
        Node walker = head;     ] 
        Node runner = head;
        // 前面指針每次走兩步,直到指向最后一個(gè)結(jié)點(diǎn)脯宿,后面指針每次走一步
        while (walker.next != null) {
            walker = walker.next;
            runner = runner.next;
            if (runner.next != null) {
                runner = runner.next;
            }
        }
        return walker;
    }
  1. 從尾到頭打印單鏈表----時(shí)間復(fù)雜度O(n)
    對(duì)于這種顛倒順序的問題念颈,我們應(yīng)該就會(huì)想到棧,后進(jìn)先出连霉。所以榴芳,這一題要么自己使用棧,要么讓系統(tǒng)使用棧跺撼,也就是遞歸窟感。注意鏈表為空的情況。
public static void reversePrintListStack(Node head) {
        Stack<Node> s = new Stack<Node>();
        Node cur = head;
        while (cur != null) {
            s.push(cur);
            cur = cur.next;
        }
        while (!s.empty()) {
            cur = s.pop();
            System.out.print(cur.val + " ");
        }
    }
    /**
    使用遞歸(優(yōu)雅G妇)
     */
    public static void reversePrintListRec(Node head) {
        if (head == null) {
            return;
        } else {
            reversePrintListRec(head.next);
            System.out.print(head.val + " ");
        }
    }
  1. Merge two sorted linked list----時(shí)間復(fù)雜度為O(max(len1, len2)),O(1)的空間
    已知兩個(gè)單鏈表pHead1 和pHead2 各自有序柿祈,把它們合并成一個(gè)鏈表依然有序
    這個(gè)類似歸并排序。尤其注意兩個(gè)鏈表都為空,和其中一個(gè)為空時(shí)的情況躏嚎。

21. Merge Two Sorted Lists

還是iteration和recursion,iteration代碼太長了蜜自,由此可見遞歸的好處,代碼簡(jiǎn)介易懂
iteration注意 l1,l2挨個(gè)merge的時(shí)候?yàn)榱朔奖憬羲鳎琹1,l2在merge后指向自己next袁辈,即后移,同時(shí)head即新鏈表的當(dāng)前node也后移珠漂,另外這里也是head不確定的情況晚缩,所以用dummy

//recursion
public ListNode mergeTwoLists(ListNode l1, ListNode l2){
    if(l1 == null) return l2;
    if(l2 == null) return l1;
    if(l1.val < l2.val){
        l1.next = mergeTwoLists(l1.next, l2);
        return l1;
    } else{
        l2.next = mergeTwoLists(l1, l2.next);
        return l2;
    }
}
//iteration
public static Node mergeSortedList(Node head1, Node head2) {
        // 其中一個(gè)鏈表為空的情況,直接返回另一個(gè)鏈表頭媳危,O(1)
        if (head1 == null) {
            return head2;
        }
        if (head2 == null) {
            return head1;
        }
        Node mergeHead = null;
        // 先確定下來mergeHead是在哪里
        if (head1.val < head2.val) {
            mergeHead = head1;
            head1 = head1.next;         // 跳過已經(jīng)合并了的元素荞彼,指向已merge的node的next
            mergeHead.next = null;  // 斷開mergeHead和后面的聯(lián)系
        } else {
            mergeHead = head2;
            head2 = head2.next;
            mergeHead.next = null;
        }
        Node mergeCur = mergeHead;
        while (head1 != null && head2 != null) {
            if (head1.val < head2.val) {
                mergeCur.next = head1;       // 把找到較小的元素合并到merge中
                head1 = head1.next;              // 跳過已經(jīng)合并了的元素
                mergeCur = mergeCur.next;    // 找到下一個(gè)準(zhǔn)備合并的元素
                mergeCur.next = null;            // 斷開mergeCur和后面的聯(lián)系
            } else {
                mergeCur.next = head2;
                head2 = head2.next;
                mergeCur = mergeCur.next;
                mergeCur.next = null;
            }
        }
        // 合并剩余的元素,這個(gè)很重要待笑,而且大部分merge算法最后都需要merge剩余東西這一步
        if (head1 != null) {
            mergeCur.next = head1;
        } else if (head2 != null) {
            mergeCur.next = head2;
        }
        return mergeHead;
    }

23. Merge k Sorted Lists

根據(jù)priority queue的特性鸣皂,我們可以通過重寫compare方法利用priority queue實(shí)現(xiàn),還有dummy暮蹂,從后向前拼接寞缝。
和下面sort里179一樣,都重寫了compare仰泻。一個(gè)是sort方法內(nèi)荆陆,一個(gè)是priority queue

      public ListNode mergeKLists(ListNode[] lists) {
          if (lists==null||lists.length==0) return null;
          PriorityQueue<ListNode> queue= new PriorityQueue<ListNode>(lists.length,new Comparator<ListNode>(){
              @Override
              /*
              1. 這里compare方法可以直接return n1.val-n2.val;
              */
              public int compare(ListNode n1, ListNode n2){
                  if(n1.val<n2.val) return -1;
                  else if(n1.val==n2.val) return 0;
                  else return 1;
              }
          });
          ListNode dummy = new ListNode(0);
          ListNode tail = dummy;
          for(ListNode n:lists){
              if(n!=null) queue.add(n);
          }
          while(!queue.isEmpty()){
              tail.next = queue.poll();
              tail=tail.next;
              if(tail.next!=null){
                  queue.add(tail.next);
              } 
          }
          return dummy.next;
      }
  1. 判斷一個(gè)單鏈表中是否有環(huán)----時(shí)間復(fù)雜度為O(n)
    這里也是用到兩個(gè)指針集侯。如果一個(gè)鏈表中有環(huán)被啼,也就是說用一個(gè)指針去遍歷,是永遠(yuǎn)走不到頭的棠枉。因此浓体,我們可以用兩個(gè)指針去遍歷,一個(gè)指針一次走兩步辈讶,一個(gè)指針一次走一步命浴,如果有環(huán),兩個(gè)指針肯定會(huì)在環(huán)中相遇贱除。

141. Linked List Cycle

  1. 用雙指針的思路咳促,walker moves step by step. runner moves two steps at time. if the Linked List has a cycle walker and runner will meet at some
    point.
  2. 解法代碼下一題中其實(shí)是包含的,但我還是把這個(gè)代碼貼出來了勘伺,因?yàn)榕卸l件那里需要注意,這道題的寫法是褂删,先判斷了head==null飞醉,之后while中判斷runner.next和runner.next.next,個(gè)人理解是runner跑的快,需要注意判斷runner而不是walker缅帘。下一題的寫法看起來跟這個(gè)不同轴术,其實(shí)一樣
public boolean hasCycle(ListNode head) {
            if(head==null) return false;
            ListNode walker = head;
            ListNode runner = head;
            // runner跑的快,在前面钦无,所以判斷runner.next, runner.next.next
            while(runner.next!=null&&runner.next.next!=null){
                walker = walker.next;
                runner = runner.next.next;
                if(walker==runner) return true;
            }
            return false;
        }

142. Linked List Cycle2

關(guān)于判定條件的一個(gè)問題上道題中解釋了
這個(gè)題目的思路不太好想逗栽,discuss中有一個(gè)很好的解釋,貼過來失暂,其中關(guān)鍵的兩點(diǎn)是彼宠,walker走過的距離和cycle長度的關(guān)系,以及walker,runner相遇之后再通過head和walker一齊走弟塞,相遇點(diǎn)是cycle起點(diǎn)這層關(guān)系

Explanations

Definitions:
Cycle = length of the cycle, if exists.
C is the beginning of Cycle, S is the distance of slow pointer from C when slow pointer meets fast pointer.
Distance(slow) = C + S, Distance(fast) = 2 * Distance(slow) = 2 * (C + S). To let slow poiner meets fast pointer, only if fast pointer run 1 cycle more than slow pointer. Distance(fast) - Distance(slow) = Cycle
=> 2 * (C + S) - (C + S)    = Cycle
=>  C + S = Cycle
=>  C = Cycle - S
=> This means if slow pointer runs (Cycle - S) more, it will reaches C. So at this time, if there's another point2(we use head Here) running from head
=> After C distance, point2 will meet slow pointer at C, where is the beginning of the cycle.
public ListNode detectCycle(ListNode head) {
            ListNode walker = head;
            ListNode runner = head;
            //這里不加runner.next.next!=null也ac
            while(runner!=null&&runner.next!=null&&runner.next.next!=null){
                runner = runner.next.next;
                walker = walker.next;
                if(runner==walker){
                    while(head!=walker){
                        head = head.next;
                        walker = walker.next;
                    }
                    return walker;
                }
            }
            return null;
        }
  1. 判斷兩個(gè)單鏈表是否相交----時(shí)間復(fù)雜度為O(len1+len2)凭峡,因?yàn)橹恍枰粋€(gè)額外指針保存最后一個(gè)節(jié)點(diǎn)地址,空間復(fù)雜度為O(1)决记。
    如果兩個(gè)鏈表相交于某一節(jié)點(diǎn)摧冀,那么在這個(gè)相交節(jié)點(diǎn)之后的所有節(jié)點(diǎn)都是兩個(gè)鏈表所共有的。也就是說系宫,如果兩個(gè)鏈表相交索昂,那么最后一個(gè)節(jié)點(diǎn)肯定是共有的。先遍歷第一個(gè)鏈表扩借,記住最后一個(gè)節(jié)點(diǎn)椒惨,然后遍歷第二個(gè)鏈表,到最后一個(gè)節(jié)點(diǎn)時(shí)和第一個(gè)鏈表的最后一個(gè)節(jié)點(diǎn)做比較往枷,如果相同框产,則相交,否則不相交错洁。
public static boolean isIntersect(Node head1, Node head2) {
        if (head1 == null || head2 == null) {
            return false;
        }

        Node tail1 = head1;
        // 找到鏈表1的最后一個(gè)節(jié)點(diǎn)
        while (tail1.next != null) {
            tail1 = tail1.next;
        }

        Node tail2 = head2;
        // 找到鏈表2的最后一個(gè)節(jié)點(diǎn)
        while (tail2.next != null) {
            tail2 = tail2.next;
        }

        return tail1 == tail2;
    }
  1. 求兩個(gè)單鏈表相交的第一個(gè)節(jié)點(diǎn)----時(shí)間復(fù)雜度秉宿,O(len1+len2)
    對(duì)第一個(gè)鏈表遍歷,計(jì)算長度len1屯碴,同時(shí)保存最后一個(gè)節(jié)點(diǎn)的地址描睦。
    對(duì)第二個(gè)鏈表遍歷,計(jì)算長度len2导而,同時(shí)檢查最后一個(gè)節(jié)點(diǎn)是否和第一個(gè)鏈表的最后一個(gè)節(jié)點(diǎn)相同忱叭,若不相同,不相交今艺,結(jié)束韵丑。
    兩個(gè)鏈表均從頭節(jié)點(diǎn)開始,假設(shè)len1大于len2虚缎,那么將第一個(gè)鏈表先遍歷len1-len2個(gè)節(jié)點(diǎn)撵彻,此時(shí)兩個(gè)鏈表當(dāng)前節(jié)點(diǎn)到第一個(gè)相交節(jié)點(diǎn)的距離就相等了,然后一起向后遍歷,知道兩個(gè)節(jié)點(diǎn)的地址相同陌僵。
 * 
     *              ----    len2
     *                   |__________
     *                   |
     *       ---------   len1
     *       |---|<- len1-len2
     */
    public static Node getFirstCommonNode(Node head1, Node head2) {
        if (head1 == null || head2 == null) {
            return null;
        }
        int len1 = 1;
        Node tail1 = head1;
        while (tail1.next != null) {
            tail1 = tail1.next;
            len1++;
        }

        int len2 = 1;
        Node tail2 = head2;
        while (tail2.next != null) {
            tail2 = tail2.next;
            len2++;
        }

        // 不相交直接返回NULL
        if (tail1 != tail2) {
            return null;
        }

        Node n1 = head1;
        Node n2 = head2;

        // 略過較長鏈表多余的部分
        if (len1 > len2) {
            int k = len1 - len2;
            while (k != 0) {
                n1 = n1.next;
                k--;
            }
        } else {
            int k = len2 - len1;
            while (k != 0) {
                n2 = n2.next;
                k--;
            }
        }

        // 一起向后遍歷轴合,直到找到交點(diǎn)
        while (n1 != n2) {
            n1 = n1.next;
            n2 = n2.next;
        }

        return n1;
    }

160. Intersection of Two Linked Lists

  1. 一個(gè)general的方法, 比較兩個(gè)linked list的長度,把較長的一個(gè)鏈表后移幾位碗短,從長度和另一鏈表相等處開始比較node是否相同受葛。
    一開始在想相交之后還會(huì)不會(huì)分開,比如一開始就相交偎谁,那長度不等情況下先向后移就說不過去了总滩,但是這里應(yīng)該是利用了鏈表特性,每個(gè)node都指向另一個(gè)node搭盾,所以相交之后就一定都一樣了咳秉。
  2. 一個(gè)很機(jī)智的方法,感覺用到了類似single linked list中判斷是否有cycle時(shí)候用的runner 和walker雙指針的方法鸯隅,這個(gè)題中的“雙指針”總會(huì)在intersection處相遇或者沒有intersection在最后的null相遇.
    disscuss區(qū)大神的分析:
  3. use two iterations here. In the first iteration, we will reset the pointer of one linkedlist to the head of another linkedlist after it reaches the tail node. In the second iteration, we will move two pointers until they points to the same node. Our operations in first iteration will help us counteract the difference.
    So if two linkedlist intersects, the meeting point in second iteration must be the intersection point. If the two linked lists have no intersection at all, then the meeting pointer in second iteration must be the tail node of both lists, which is null
  4. The problem description especially required the code to run in O(n) time and O(1) space. Thus I came up with the most direct way.
      Just count the lengths of both lists, set two pointers from the list heads, align them to equipotential position and move'em forward until they coincide.
      That would be the answer we seek.
      Time complexity should be O(n + m), if you name the lengths of both lists to be "n" and "m". Extra space required is O(1).
  5. Notice:只貼一下第二個(gè)方法澜建,第一個(gè)方法很簡(jiǎn)單,分別遍歷鏈表直到空蝌以,通過counter獲取長度炕舵,然后通過兩個(gè)長度差值移動(dòng)指向較長鏈表的node的位置,在等長之后比較node是否相同跟畅,是就返回該node咽筋。
public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
          if(headA == null || headB == null) return null;
          ListNode a = headA;
          ListNode b = headB;
          while( a != b){
                  a = a == null? headB : a.next;
                  b = b == null? headA : b.next;    
            }
          return a;
}
  1. 已知一個(gè)單鏈表中存在環(huán),求進(jìn)入環(huán)中的第一個(gè)節(jié)點(diǎn)
    上面貼的leetcode142
    首先判斷是否存在環(huán)徊件,若不存在結(jié)束奸攻。在環(huán)中的一個(gè)節(jié)點(diǎn)處斷開(當(dāng)然函數(shù)結(jié)束時(shí)不能破壞原鏈表),這樣就形成了兩個(gè)相交的單鏈表虱痕,求進(jìn)入環(huán)中的第一個(gè)節(jié)點(diǎn)也就轉(zhuǎn)換成了求兩個(gè)單鏈表相交的第一個(gè)節(jié)點(diǎn)睹耐。參考代碼如下:
    /**
     * 求進(jìn)入環(huán)中的第一個(gè)節(jié)點(diǎn) 用快慢指針做(本題用了Crack the Coding Interview的解法,因?yàn)楦?jiǎn)潔易懂2壳獭)
     */
    public static Node getFirstNodeInCycle(Node head) {
        Node slow = head;
        Node fast = head;

        // 1) 找到快慢指針相遇點(diǎn)
        while (fast != null && fast.next != null) {
            slow = slow.next;
            fast = fast.next.next;
            if (slow == fast) { // Collision
                break;
            }
        }

        // 錯(cuò)誤檢查硝训,這是沒有環(huán)的情況
        if (fast == null || fast.next == null) {
            return null;
        }

        // 2)現(xiàn)在,相遇點(diǎn)離環(huán)的開始處的距離等于鏈表頭到環(huán)開始處的距離新思,
        // 這樣窖梁,我們把慢指針放在鏈表頭,快指針保持在相遇點(diǎn)夹囚,然后
        // 同速度前進(jìn)纵刘,再次相遇點(diǎn)就是環(huán)的開始處!
        slow = head;
        while (slow != fast) {
            slow = slow.next;
            fast = fast.next;
        }

        // 再次相遇點(diǎn)就是環(huán)的開始處
        return fast;
    }
  1. 給出一單鏈表頭指針pHead和一節(jié)點(diǎn)指針pToBeDeleted荸哟,O(1)時(shí)間復(fù)雜度刪除節(jié)點(diǎn)pToBeDeleted----總體的平均時(shí)間復(fù)雜度還是O(1)
    對(duì)于刪除節(jié)點(diǎn)假哎,我們普通的思路就是讓該節(jié)點(diǎn)的前一個(gè)節(jié)點(diǎn)指向該節(jié)點(diǎn)的下一個(gè)節(jié)點(diǎn)蛔翅,這種情況需要遍歷找到該節(jié)點(diǎn)的前一個(gè)節(jié)點(diǎn),時(shí)間復(fù)雜度為O(n)位谋。對(duì)于鏈表,鏈表中的每個(gè)節(jié)點(diǎn)結(jié)構(gòu)都是一樣的堰燎,所以我們可以把該節(jié)點(diǎn)的下一個(gè)節(jié)點(diǎn)的數(shù)據(jù)復(fù)制到該節(jié)點(diǎn)掏父,然后刪除下一個(gè)節(jié)點(diǎn)即可。要注意最后一個(gè)節(jié)點(diǎn)的情況秆剪,這個(gè)時(shí)候只能用常見的方法來操作赊淑,先找到前一個(gè)節(jié)點(diǎn),但總體的平均時(shí)間復(fù)雜度還是O(1)仅讽。參考代碼如下:
public void delete(Node head, Node toDelete){  
        if(toDelete == null){  
            return;  
        }  
        if(toDelete.next != null){          // 要?jiǎng)h除的是一個(gè)中間節(jié)點(diǎn)  
            toDelete.val = toDelete.next.val;       // 將下一個(gè)節(jié)點(diǎn)的數(shù)據(jù)復(fù)制到本節(jié)點(diǎn)!  
            toDelete.next = toDelete.next.next;  
        }  
        else{       // 要?jiǎng)h除的是最后一個(gè)節(jié)點(diǎn)陶缺!  
            if(head == toDelete){       // 鏈表中只有一個(gè)節(jié)點(diǎn)的情況    
                head = null;  
            }else{  
                Node node = head;  
                while(node.next != toDelete){   // 找到倒數(shù)第二個(gè)節(jié)點(diǎn)  
                    node = node.next;  
                }  
                node.next = null;  
            }  
        }  
    }  

規(guī)律總結(jié)

  1. DummyNode
    做鏈表題目時(shí),如果head可能被改變洁灵,我們需要?jiǎng)?chuàng)建一個(gè)虛擬節(jié)點(diǎn)饱岸,叫DummyNode,把頭部掛在它的后面徽千。這樣就算頭部變化了之后苫费,只要返回DummyNode.next就能輕松得到新頭部。
  2. Merge LinkedList是相當(dāng)基礎(chǔ)的題目双抽,merge的半成品代碼上面也有提到百框。
  3. Reverse linkedList最簡(jiǎn)單的寫法就是創(chuàng)建DummyNode,然后把舊的鏈表不斷插入到DummyNode的后面牍汹,就能輕松地返回鏈表了铐维。
  4. 操作鏈表的時(shí)候,我們經(jīng)常會(huì)改變某些Node慎菲。如果后面還需要再用到被改變掉節(jié)點(diǎn)的原始值嫁蛇,請(qǐng)一定記得用tmp先把它保存起來。

ref:

  1. http://blog.csdn.net/luckyxiaoqiang/article/details/7393134
  2. http://blog.csdn.net/fightforyourdream/article/details/16353519
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末钧嘶,一起剝皮案震驚了整個(gè)濱河市棠众,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌有决,老刑警劉巖闸拿,帶你破解...
    沈念sama閱讀 206,126評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異书幕,居然都是意外死亡新荤,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,254評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門台汇,熙熙樓的掌柜王于貴愁眉苦臉地迎上來苛骨,“玉大人篱瞎,你說我怎么就攤上這事⊙髦ィ” “怎么了俐筋?”我有些...
    開封第一講書人閱讀 152,445評(píng)論 0 341
  • 文/不壞的土叔 我叫張陵,是天一觀的道長严衬。 經(jīng)常有香客問我澄者,道長,這世上最難降的妖魔是什么请琳? 我笑而不...
    開封第一講書人閱讀 55,185評(píng)論 1 278
  • 正文 為了忘掉前任粱挡,我火速辦了婚禮,結(jié)果婚禮上俄精,老公的妹妹穿的比我還像新娘询筏。我一直安慰自己,他們只是感情好竖慧,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,178評(píng)論 5 371
  • 文/花漫 我一把揭開白布嫌套。 她就那樣靜靜地躺著,像睡著了一般测蘑。 火紅的嫁衣襯著肌膚如雪灌危。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 48,970評(píng)論 1 284
  • 那天碳胳,我揣著相機(jī)與錄音勇蝙,去河邊找鬼。 笑死挨约,一個(gè)胖子當(dāng)著我的面吹牛味混,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播诫惭,決...
    沈念sama閱讀 38,276評(píng)論 3 399
  • 文/蒼蘭香墨 我猛地睜開眼翁锡,長吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來了夕土?” 一聲冷哼從身側(cè)響起馆衔,我...
    開封第一講書人閱讀 36,927評(píng)論 0 259
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎怨绣,沒想到半個(gè)月后角溃,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,400評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡篮撑,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,883評(píng)論 2 323
  • 正文 我和宋清朗相戀三年减细,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片赢笨。...
    茶點(diǎn)故事閱讀 37,997評(píng)論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡未蝌,死狀恐怖驮吱,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情萧吠,我是刑警寧澤左冬,帶...
    沈念sama閱讀 33,646評(píng)論 4 322
  • 正文 年R本政府宣布,位于F島的核電站纸型,受9級(jí)特大地震影響又碌,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜绊袋,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,213評(píng)論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望铸鹰。 院中可真熱鬧癌别,春花似錦、人聲如沸蹋笼。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,204評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽剖毯。三九已至圾笨,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間逊谋,已是汗流浹背擂达。 一陣腳步聲響...
    開封第一講書人閱讀 31,423評(píng)論 1 260
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留胶滋,地道東北人板鬓。 一個(gè)月前我還...
    沈念sama閱讀 45,423評(píng)論 2 352
  • 正文 我出身青樓,卻偏偏與公主長得像究恤,于是被迫代替她去往敵國和親俭令。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,722評(píng)論 2 345

推薦閱讀更多精彩內(nèi)容

  • 背景 一年多以前我在知乎上答了有關(guān)LeetCode的問題, 分享了一些自己做題目的經(jīng)驗(yàn)部宿。 張土汪:刷leetcod...
    土汪閱讀 12,724評(píng)論 0 33
  • 目錄 1. 棧和隊(duì)列1.用兩個(gè)隊(duì)列實(shí)現(xiàn)棧2.用兩個(gè)棧實(shí)現(xiàn)隊(duì)列3.實(shí)現(xiàn)一個(gè)棧抄腔,可以用常數(shù)級(jí)時(shí)間找出棧中的最小值4.判...
    MigrationUK閱讀 3,024評(píng)論 4 20
  • 2. Add Two Numbers 先初始化兩個(gè)結(jié)點(diǎn),一個(gè)用來做head理张,一個(gè)作為指引node不斷向下延續(xù)的指針...
    Morphiaaa閱讀 915評(píng)論 0 0
  • 鏈表 概念 說到鏈表赫蛇,coder們都不會(huì)陌生,在日常開發(fā)中或多或少都會(huì)用到它涯穷。它是鏈?zhǔn)酱鎯?chǔ)的線性表棍掐,簡(jiǎn)稱鏈表。鏈表...
    扈扈哈嘿閱讀 2,076評(píng)論 0 5
  • 相信有很多初識(shí)簡(jiǎn)書的朋友掘殴,會(huì)像我一樣,很在乎粉絲的增減粟誓,多一個(gè)關(guān)注會(huì)高興好一陣奏寨,而今天,有一個(gè)人關(guān)注了我鹰服,我們沒有...
    左臉美麗i閱讀 277評(píng)論 4 3