1. 程式人生 > >程式設計師程式碼面試指南 —— 連結串列問題(三)

程式設計師程式碼面試指南 —— 連結串列問題(三)

題目:複製含有隨機指標節點的連結串列
描述:有一種連結串列節點類描述如下:
public class Node {
public int value;
public Node next;
public Node rand;
public Node(int data){
this.value = data;
}
}

Node 類中的value是節點值,next指標和正常單鏈表中next指標的意義一樣,都指向下一個節點,rand指標是Node類中新增的指標,這個指標可能指向連結串列中的任意一個節點,也可能指向null。
  給定一個由Node節點型別組成的無環單鏈表的頭節點head,請實現一個函式完成這個連結串列中所有結構的複製,並返回複製的新連結串列的頭結點。例如連結串列 1 —> 2 —>3 —> null,假如:1的rand指標指向3,2的rand指標指向null,3的rand指標指向  1,複製後的連結串列也應該具有這種關係
  
思路:
  方法一:描述對應關係,可以考慮散列表
  1) 從左到右遍歷連結串列,對每個節點都生成對應的副本節點,然後將對對應關係放入雜湊map中
步驟:
  1 完成後,原連結串列沒有任何變化,每一個副本節點的next和rand指標都指向null
  2.再從左到右遍歷連結串列,此時就可以設定每一個副本節點的rend和next指標
例如:原連結串列 1 —>2 —>3 —>null,假設1的rand指標指向3,2的rand指標指向null,3的rand指標指向1.遍歷到1節點的時候,可以從map中得到1的副本節點1’ ,1的next指向2 ,所以從map中找到2的副本 2’,令1’->2’,同時指定1’的rand指標指向
  3.經過兩次遍歷之後,返回散列表中 key = head 的值即可
程式碼實現:

private static Node copyChain(Node head) {
           HashMap<Node,Node> map = new HashMap();
      Node cur = head;
      while(cur != null){
        map.put(cur,new Node(cur.value));
        cur = cur.next;
      }
      cur = head;
      while (cur != null){
        map.get(cur).next = map.get(cur.next);
        map.get(cur).rand = map.get(cur.rand);
        cur = cur.next;
      }
      return map.get(head);
  }

方法二:用有限的變數去完成該功能
  1) 從左到右遍歷連結串列,把每個節點cur都複製一份copy,然後把copy放在cur和下一個要遍歷的節點中間 1—>1’—>2—>2’—>3—>3’
  2)再從左到右遍歷連結串列,在遍歷時設定每一個副本節點的rand
  3)步驟2完成之後,節點1,2,3之間的rand沒有變化,而節點1’ 2’ 3’之間的rand關係也被正確設定了,只要將其分離即可
程式碼實現:

private static Node copyChain(Node head) {
    if (head == null) {
      return null;
    }
    Node cur = head;
    Node next = null;
    // 複製節點
    while (cur != null) {
      next = cur.next;
      cur.next = new Node(cur.value);
      cur.next.next = next;
    }
    cur = head;
    Node curCopy = null;
 
    // 設定複製節點的rand指標
    while (cur != null) {
      next = cur.next.next;
      curCopy = cur.next;
      curCopy.rand = cur.rand != null ? cur.rand.next : null;
      cur = next;
    }
    Node res = head.next;
    cur = head;
    
    //拆分
    while (cur != null){
      next = cur.next.next;
      curCopy = cur.next;
      cur.next = next;
      curCopy.next = next != null ? next.next:null;
      cur = next;
    }
    return res;
  }

題目:兩個單鏈表生成相加連結串列
問題描述:
  假設連結串列中的每一個節點的值都在0-9之間,那麼連結串列整體就可以代表一個整數,例如9 -> 3 ->7,可以代表937,給定這兩種連結串列的頭節點head1和head2,請生成代表兩個數相加值的結果連結串列
思路:
  可以對連結串列求其逆序連結串列,求完之後,將兩數相加,給定一個是否進位的進位標值sign,即可。
程式碼實現:

public class AddChain {
  public static void main(String[] args) {
    // init()
    Node head1 = new Node(9);
    Node node1 = new Node(3);
    Node node2 = new Node(7);
 
    Node head2 = new Node(6);
    Node node3 = new Node(3);
 
    head1.next = node1;
    node1.next = node2;
 
    head2.next = node3;
 
    Node reHead1 = ReverNode(head1);
    Node reHead2 = ReverNode(head2);
 
    Node res = add(reHead1, reHead2);
    res = ReverNode(res);
    Node h = res;
    while (h != null) {
      System.out.print(h.value + " ");
      h = h.next;
    }
  }
 
  private static Node add(Node head1, Node head2) {
    Node head = new Node(0);
    Node h = head;
    int ca = 0;
    while (head1 != null && head2 != null) {
      int res = head1.value + head2.value + ca;
      ca = 0;
      if (res > 9) {
        res = res - 10;
        ca++;
      }
      h.next = new Node(res);
      h = h.next;
      head1 = head1.next;
      head2 = head2.next;
    }
    
    while (head1 != null) {
      int res = head1.value + ca;
      ca = 0;
      if (res > 9) {
        res = res - 10;
        ca++;
      }
      h.next = new Node(res);
      h = h.next;
      head1 = head1.next;
    }
 
    while (head2 != null) {
      int res = head2.value + ca;
      ca = 0;
      if (res > 9) {
        res = res - 10;
        ca++;
      }
      h.next = new Node(res);
      h = h.next;
      head2 = head2.next;
    }
 
    if(ca != 0){
        h.next = new Node(ca);
        h = h.next;
    }
    return head.next;
  }
 
  private static Node ReverNode(Node head) {
    Node next = null;
    Node pre = null;
    while (head != null) {
      next = head.next;
      head.next = pre;
      pre = head;
      head = next;
    }
    return pre;
  }
}