劍指offer(Java)-複雜鏈表的複製

題目描述:

複製一個複雜鏈表,在複雜鏈表中,每一個結點除了有一個next指針指向下一個結點外,還有一個sbiling指向鏈表中的任意結點或者null。java

下圖是一個複雜鏈表的示例,Null的指針沒有畫出。
這裏寫圖片描述node

解題思路:

1.很直觀的解法就是分紅兩步:

1).複製原始鏈表上的每個結點,並用next指針連起來。
2).複製sbiling指針。
可是複製sbiling指針時須要比較高的複雜度。
以上圖爲例,若是咱們要複製B對應B’的的sbiling指針,那就是要找到E’,想要找到E’只能根據
B到E要走的步數 = B’到E’要走的步數
然而又如D.sbiling = B,指向的結點在它的前面,而鏈表並無指向前一個元素的指針,因此,每次都只能根據從鏈表頭結點到目標的結點的步數來找到sbiling應該指向的元素
這種方法顯然效率過低,時間複雜度達到了O(n*n)。算法

2.書中提到了利用哈希表存儲(N, N’)的配對信息的方法

這是一個在時間上很高效的方法,在查找上,利用哈希表的高效性。可是缺點在於要用額外的空間。app

上述方法的時間主要花在定位結點的m_pSibling上面,咱們試着在這方面作優化。仍是分兩步:第一步仍然是複製原始鏈表上的每一個結點N,並建立 N’,而後把這些建立出來的結點連接起來。同時咱們把<N, N’>的配對信息放到一個哈希表中。第二步仍是設置複製後的鏈表上每一個結點的m_pSibling。若是在原始鏈表中結點N的m_pSibling 指向結點S,那麼在複製後的鏈表中,對應的N’應該指向S’。因爲有了哈希表,能夠用O(1)的時間根據S找到S’。這種方法至關於用空間換時間,以 O(n)的空間消耗把時間複雜度由O(n^2)下降到O(n)。dom

(注:哈希表中的每個配對(pair)的Key是原始鏈表的結點,Value是Key中 結點的對應的拷貝結點。這樣在哈希表中,就能夠在O(1)的時間裏,找到原始結點對應的拷貝出來的結點。好比想求得N’的m_pSibling所指向的 S’,能夠由N的m_pSibling求得S,而<S, S’>的配對信息就在哈希表中,能夠用O(1)時間求得。)ide

3.更爲高效的一種不利用輔助空間的方法

這個方法的巧妙之處在於利用鏈表結點自己記錄sbiling指針的位置。
分紅三個步驟
1).根據原始鏈表的每一個結點N建立對應的N’,並把N’連在N的後面。
以下圖:
這裏寫圖片描述優化

2)看到上圖咱們就應該知道這個算法的巧妙之處了,B’.sbiling就記錄在B.sbiling.next,這一步就是經過這個方法設置sbiling指針了。ui

3).將兩個鏈表斷開。this

 

package cglib;spa


class ComplexListNode
{
int data;
ComplexListNode next;
ComplexListNode sibling;

@Override
public String toString() {
    StringBuilder sb = new StringBuilder();
    sb.append("data = " + data);
    sb.append(", next = " + (next == null ? "null" : next.data));
    sb.append(", sbiling = " + (sibling == null ? "null" : sibling.data));
    return sb.toString();
}
}


public class DeleteNode{
    

        public static void copyList(ComplexListNode head){

            ComplexListNode node = head;
            while(node != null){

                ComplexListNode copyNode = new ComplexListNode();
                copyNode.data = node.data;//1的數據給01
                copyNode.next = node.next;//1指向2的指針給01,至關於01指向2
                copyNode.sibling = null;
                 //1->2->3,變成1->01->2->02->3->03
                node.next = copyNode;//1指向01
                node = copyNode.next;//而後以2開始又繼續下一個while循環
            }


        }
          //1->01->2->02->3->03,1--->3,01--->03
        public static void setSbiling(ComplexListNode head){
            ComplexListNode node = head;

// 當前處理的結點sibling字段不爲空,則要設置其複製結點的sibling字段


            while(node != null){
                ComplexListNode copyNode = node.next;//01開始
                if(node.sibling != null){//1指向3
                    copyNode.sibling = node.sibling.next;//01指向03,至關於1指向3,3的下一個結點就是03
                }
                node = copyNode.next;
            }
        }
      //1->01->2->02->3->03,1--->3,01--->03
        public static ComplexListNode disConnectList(ComplexListNode head){
            ComplexListNode node = head;
            ComplexListNode copyHead = null;
            ComplexListNode copyNode = null;

            if(node != null){// node 不爲空才能進行下面的while循環
                copyHead = node.next;//01爲頭
                copyNode = node.next;
                node.next = copyNode.next;//1的下一個01變成01的下一個2
                node = node.next;//而後將2做爲下一個結點進入下面的while循環
            }

            while(node != null){

                copyNode.next = node.next;//01的下一個就是02, //把偶數位置的結點連接起來就是複製出來的新鏈表
                copyNode = copyNode.next;//以02開始進行下一個, //把奇數位置的結點連接起來就是原始鏈表  

                node.next = copyNode.next;//2的下一個就是3,至關於02的下一個
                node = node.next;//以3做爲結點進行下一個
            }

            return copyHead;
        }

        public static ComplexListNode copy(ComplexListNode head){
            copyList(head);
            setSbiling(head);
            return disConnectList(head);
        }

        public static void main(String[] args) {

            ComplexListNode head = new ComplexListNode();
            head.data = 1;

            ComplexListNode node2 = new ComplexListNode();
            node2.data = 2;

            ComplexListNode node3 = new ComplexListNode();
            node3.data = 3;

            ComplexListNode node4 = new ComplexListNode();
            node4.data = 4;

            ComplexListNode node5 = new ComplexListNode();
            node5.data = 5;

            head.next = node2;
            head.sibling = node3;

            node2.next = node3;
            node2.sibling = node5;

            node3.next = node4;

            node4.next = node5;
            node4.sibling = node2;

            ComplexListNode copyHead = copy(head);

            ComplexListNode node = copyHead;
            while(node != null){
                System.out.println(node);
                node = node.next;
            }

        }
}


輸出:

data = 1, next = 2, sbiling = 3
data = 2, next = 3, sbiling = 5
data = 3, next = 4, sbiling = null
data = 4, next = 5, sbiling = 2
data = 5, next = null, sbiling = null

 

下面是map實現:

 

package cglib;

import java.util.HashMap;

class RandomListNode
{

int data;

RandomListNode next = null;

RandomListNode sibling = null;

 

RandomListNode(int data) {

    this.data = data;

}

@Override
public String toString() {
    StringBuilder sb = new StringBuilder();
    sb.append("data = " + data);
    sb.append(", next = " + (next == null ? "null" : next.data));
    sb.append(", sbiling = " + (sibling == null ? "null" : sibling.data));
    return sb.toString();
}
}


public class DeleteNode{
    

     public static RandomListNode Clone(RandomListNode pHead)
    
        {
    
            if(pHead == null)
                return null;
            

            HashMap<RandomListNode, RandomListNode> map = new HashMap<>();
    
            RandomListNode newHead = new RandomListNode(pHead.data);
    
            RandomListNode pre = pHead, newPre = newHead;//pre用於掃描原鏈表
          //newHead指向複製鏈表,newPre用於掃描複製鏈表
            map.put(pre, newPre);
    
            while(pre.next != null){
    
                newPre.next = new RandomListNode(pre.next.data);
    
                pre = pre.next;
    
                newPre = newPre.next;
    
                map.put(pre, newPre);
    
            }
    
            pre = pHead;
    
            newPre = newHead;
    
            while(newPre != null){
    
                newPre.sibling = map.get(pre.sibling);
    
                pre = pre.next;
    
                newPre = newPre.next;
    
            }
    
            return newHead;
    
        
        }
    
     public static void main(String[] args) {

        RandomListNode head = new RandomListNode(1);
        

        RandomListNode node2 = new RandomListNode(2);
         

         RandomListNode node3 = new RandomListNode(3);
        

         RandomListNode node4 = new RandomListNode(4);
        

         RandomListNode node5 = new RandomListNode(5);
         

         head.next = node2;
         head.sibling = node3;

         node2.next = node3;
         node2.sibling = node5;

         node3.next = node4;

         node4.next = node5;
         node4.sibling = node2;

         RandomListNode copyHead = Clone(head);

         

         RandomListNode node = copyHead;
         while(node != null){
             System.out.println(node);
             node = node.next;
         }
         

     }
}


輸出:

data = 1, next = 2, sbiling = 3 data = 2, next = 3, sbiling = 5 data = 3, next = 4, sbiling = null data = 4, next = 5, sbiling = 2 data = 5, next = null, sbiling = null

相關文章
相關標籤/搜索