【题目】
给定一个单链表的头节点head,链表长度为N,如果N为偶数,那么前N/2个节点算作左半区,后N/2个节点算作右半区;如果N为奇数,那么前N/2个节点算作左半区,后N/2+1个节点算作右半区。
左半区从左到右依次记为L1 -> L2 -> ...,右半区从左到右依次记为R1 -> R2 -> ...,请将单链表调整成L1 -> R1 -> L2 -> R2 -> ...的形式
例如,1 -> null,调整成1 -> null
1 -> 2 -> null,调整成1 -> 2 -> null
1 -> 2 -> 3 -> null,调整成1 -> 2 -> 3 -> null
1 -> 2 -> 3 -> 4 -> null,调整成1 -> 3 -> 2 -> 4 -> null
1 -> 2 -> 3 -> 4 -> 5 -> null,调整成1 -> 3 -> 2 -> 4 -> 5 -> null
1 -> 2 -> 3 -> 4 -> 5 -> 6 -> null,调整成1 -> 4 -> 2 -> 5 -> 3 -> 6 -> null
my:
1 public void relocate(Node head) 2 { 3 if(head == null || head.next == null) 4 { 5 return; 6 }
7 Node left = getMid(head); // getMid返回的是中间节点 8 Node right = left.next; 9 left.next = null; 10 left = head; 11 12 while(left.next != null) 13 { 14 Node temp = right; 15 right = right.next; 16 temp.next = left.next; 17 left.next = temp; 18 left = temp.next; 19 } left.next = right; // 右半区的长度总是不小于左半区的长度;若右半区比左半区长,则将长的那部分直接链接到链表的尾部
24 } 25 26 public Node getMid(Node head) 27 { 28 Node temp = head; 29 Node pre = head; 30 Node next = head; 31 while(next.next != null && next.next.next != null) 32 { 33 temp = pre; 34 pre = pre.next; 35 next = next.next.next; 36 } 37 return (next.next == null) ? temp : pre; // 如果N为奇数则返回temp,为偶数则返回pre 38 }
左老师:
1 public void relocate(Node head) 2 { 3 if(head == null || head.next == null) 4 { 5 return; 6 } 7 Node mid = head; 8 Node right = head.next; // 如果是寻找一般意义上的中间节点,则此处应是right = head; 9 while(right.next != null && right.next.next != null) 10 { 11 mid = mid.next; 12 right = right.next.next; 13 } 14 right = mid.next; 15 mid.next = null; 16 mergeLR(head, right); 17 } 18 19 public void mergeLR(Node left, Node right) // 合并左右半区 20 { 21 Node next = null; 22 while(left.next != null) 23 { 24 next = right.next; 25 right.next = left.next; 26 left.next = right; 27 left = right.next; 28 right = next; 29 } 30 left.next = right; // 因为右半区的长度总是不小于左半区的,所有直接把多的右半区链接到尾部 31 }
来源:左程云老师《程序员代码面试指南》