程式設計師程式碼面試指南 —— 連結串列問題(三)
題目:複製含有隨機指標節點的連結串列
描述:有一種連結串列節點類描述如下:
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;
}
}