1. 环形单链表的约舍夫问题
题目描述:
据说著名的犹太历史学家Josephus有过以下故事:在罗马人占领桥塔帕特后,39个犹太人与Josephus 及他的朋友躲到一个洞中,39个犹太人宁愿死也不要被敌人抓到,于是决定了一个自杀方式,41个人排成一个圆圈,由第一个人开始报数,报数到3的人就自杀,然后再有下一个人重新报1,报数到3的人再自杀。这样依次下去,直到剩下最后一个人时,那个人可以自由选择自己的命运。这就是著名的约瑟夫问题。现在请用单向环形链表描述该结构并呈现整个自杀过程。
输入:一个环形单向链表的头节点head 和报数的值m。
返回:最后生存下来的节点,且这个节点自己组成环形单向链表,其他节点都删掉。
代码:
package chapter_2_listproblem;
public class Problem_06_JosephusProblem {
public static class Node {
public int value;
public Node next;
public Node(int data) {
this.value = data;
}
}
public static Node josephusKill1(Node head, int m) {
if (head == null || head.next == head || m < 1) {
return head;
}
Node last = head;
while (last.next != head) {
last = last.next;
}
int count = 0;
while (head != last) {
if (++count == m) {
last.next = head.next;
count = 0;
} else {
last = last.next;
}
head = last.next;
}
return head;
}
public static Node josephusKill2(Node head, int m) {
if (head == null || head.next == head || m < 1) {
return head;
}
Node cur = head.next;
int tmp = 1; // tmp -> list size
while (cur != head) {
tmp++;
cur = cur.next;
}
tmp = getLive(tmp, m); // tmp -> service node position
while (--tmp != 0) {
head = head.next;
}
head.next = head;
return head;
}
public static int getLive(int i, int m) {
if (i == 1) {
return 1;
}
return (getLive(i - 1, m) + m - 1) % i + 1;
}
public static void printCircularList(Node head) {
if (head == null) {
return;
}
System.out.print("Circular List: " + head.value + " ");
Node cur = head.next;
while (cur != head) {
System.out.print(cur.value + " ");
cur = cur.next;
}
System.out.println("-> " + head.value);
}
public static void main(String[] args) {
Node head1 = new Node(1);
head1.next = new Node(2);
head1.next.next = new Node(3);
head1.next.next.next = new Node(4);
head1.next.next.next.next = new Node(5);
head1.next.next.next.next.next = head1;
printCircularList(head1);
head1 = josephusKill1(head1, 3);
printCircularList(head1);
Node head2 = new Node(1);
head2.next = new Node(2);
head2.next.next = new Node(3);
head2.next.next.next = new Node(4);
head2.next.next.next.next = new Node(5);
head2.next.next.next.next.next = head2;
printCircularList(head2);
head2 = josephusKill2(head2, 3);
printCircularList(head2);
}
}
2. 将单向链表按某值划分成左边小、中间相等、右边大的形式
题目描述:
给定一个单向链表的头节点 head,节点的值类型为整形,再给定一个整数 pivot。实现一个调整链表的函数,将链表调整为左部分都是值小于 pivot 的节点,中间部分都是值等于 pivot 的节点,右部分都是值大于 pivot 的节点。除这个要求外,对调整后的节点顺序没有更多的要求。
例如:链表 9->0->4->5->1,pivot=3
调整后链表可以是 1->0->4->9->5,也可以是 0->1->9->5->4。总之,满足左部分都是小于 3 的节点,中间部分都是等于 3 的节点(本例中这个部分为空),右部分都是大于 3 的节点即可。对某部分内部的节点顺序不做要求。
代码:
package chapter_2_listproblem;
public class Problem_08_SmallerEqualBigger {
public static class Node {
public int value;
public Node next;
public Node(int data) {
this.value = data;
}
}
public static Node listPartition1(Node head, int pivot) {
if (head == null) {
return head;
}
Node cur = head;
int i = 0;
while (cur != null) {
i++;
cur = cur.next;
}
Node[] nodeArr = new Node[i];
i = 0;
cur = head;
for (i = 0; i != nodeArr.length; i++) {
nodeArr[i] = cur;
cur = cur.next;
}
arrPartition(nodeArr, pivot);
for (i = 1; i != nodeArr.length; i++) {
nodeArr[i - 1].next = nodeArr[i];
}
nodeArr[i - 1].next = null;
return nodeArr[0];
}
public static void arrPartition(Node[] nodeArr, int pivot) {
int small = -1;
int big = nodeArr.length;
int index = 0;
while (index != big) {
if (nodeArr[index].value < pivot) {
swap(nodeArr, ++small, index++);
} else if (nodeArr[index].value == pivot) {
index++;
} else {
swap(nodeArr, --big, index);
}
}
}
public static void swap(Node[] nodeArr, int a, int b) {
Node tmp = nodeArr[a];
nodeArr[a] = nodeArr[b];
nodeArr[b] = tmp;
}
public static Node listPartition2(Node head, int pivot) {
Node sH = null; // small head
Node sT = null; // small tail
Node eH = null; // equal head
Node eT = null; // equal tail
Node bH = null; // big head
Node bT = null; // big tail
Node next = null; // save next node
// every node distributed to three lists
while (head != null) {
next = head.next;
head.next = null;
if (head.value < pivot) {
if (sH == null) {
sH = head;
sT = head;
} else {
sT.next = head;
sT = head;
}
} else if (head.value == pivot) {
if (eH == null) {
eH = head;
eT = head;
} else {
eT.next = head;
eT = head;
}
} else {
if (bH == null) {
bH = head;
bT = head;
} else {
bT.next = head;
bT = head;
}
}
head = next;
}
// small and equal reconnect
if (sT != null) {
sT.next = eH;
eT = eT == null ? sT : eT;
}
// all reconnect
if (eT != null) {
eT.next = bH;
}
return sH != null ? sH : eH != null ? eH : bH;
}
public static void printLinkedList(Node node) {
System.out.print("Linked List: ");
while (node != null) {
System.out.print(node.value + " ");
node = node.next;
}
System.out.println();
}
public static void main(String[] args) {
Node head1 = new Node(7);
head1.next = new Node(9);
head1.next.next = new Node(1);
head1.next.next.next = new Node(8);
head1.next.next.next.next = new Node(5);
head1.next.next.next.next.next = new Node(2);
head1.next.next.next.next.next.next = new Node(5);
printLinkedList(head1);
// head1 = listPartition1(head1, 4);
head1 = listPartition2(head1, 5);
printLinkedList(head1);
}
}
3. 复制含有随机指针节点的链表
题目描述:
node 中的 value 是节点值,next 指针和正常链表中的 next 指针的意义一样,都指向下一个节点,rand 指针是 Node 类中新增的指针,这个指针可能指向链表中的任意一个节点,也可能指向 NULL。
给定一个由 Node 节点类型组成的无环单链表的头节点 head,请实现一个函数完成这个链表中所有结构的复制,并返回复制的新链表的头节点。例如:链表1->2->3->NULL。假设 1 的 rand 指针指向 3,2 的 rand 指针指向NULL,3 的 rand 指针指向 1。复制后的链表应该也是这种结构,比如, 1‘-2’->3’->NULL,1’ 的 rand 指针指向 3,2’ 的 rand 指针指向 NULL,3’ 的 rand 指针指向 1‘,最后返回 1‘。
代码:
package chapter_2_listproblem;
import java.util.HashMap;
public class Problem_09_CopyListWithRandom {
public static class Node {
public int value;
public Node next;
public Node rand;
public Node(int data) {
this.value = data;
}
}
public static Node copyListWithRand1(Node head) {
HashMap<Node, Node> map = new HashMap<Node, Node>();
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);
}
public static Node copyListWithRand2(Node head) {
if (head == null) {
return null;
}
Node cur = head;
Node next = null;
// copy node and link to every node
while (cur != null) {
next = cur.next;
cur.next = new Node(cur.value);
cur.next.next = next;
cur = next;
}
cur = head;
Node curCopy = null;
// set copy node 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;
// split
while (cur != null) {
next = cur.next.next;
curCopy = cur.next;
cur.next = next;
curCopy.next = next != null ? next.next : null;
cur = next;
}
return res;
}
public static void printRandLinkedList(Node head) {
Node cur = head;
System.out.print("order: ");
while (cur != null) {
System.out.print(cur.value + " ");
cur = cur.next;
}
System.out.println();
cur = head;
System.out.print("rand: ");
while (cur != null) {
System.out.print(cur.rand == null ? "- " : cur.rand.value + " ");
cur = cur.next;
}
System.out.println();
}
public static void main(String[] args) {
Node head = null;
Node res1 = null;
Node res2 = null;
printRandLinkedList(head);
res1 = copyListWithRand1(head);
printRandLinkedList(res1);
res2 = copyListWithRand2(head);
printRandLinkedList(res2);
printRandLinkedList(head);
System.out.println("=========================");
head = new Node(1);
head.next = new Node(2);
head.next.next = new Node(3);
head.next.next.next = new Node(4);
head.next.next.next.next = new Node(5);
head.next.next.next.next.next = new Node(6);
head.rand = head.next.next.next.next.next; // 1 -> 6
head.next.rand = head.next.next.next.next.next; // 2 -> 6
head.next.next.rand = head.next.next.next.next; // 3 -> 5
head.next.next.next.rand = head.next.next; // 4 -> 3
head.next.next.next.next.rand = null; // 5 -> null
head.next.next.next.next.next.rand = head.next.next.next; // 6 -> 4
printRandLinkedList(head);
res1 = copyListWithRand1(head);
printRandLinkedList(res1);
res2 = copyListWithRand2(head);
printRandLinkedList(res2);
printRandLinkedList(head);
System.out.println("=========================");
}
}
4. 两个单链表生成相加链表
题目描述:
假设链表中每一个节点的值都在 0~9 之间,那么链表整体就可以代表一个整数。
例如:9->3->7,可以代表整数937。
给定两个这种链表的头节点 head1 和 head2,请生成代表两个整数相加值的结果链表。
例如:链表 1 为9->3->7,链表 2 为 6->3,最后生成新的结果链表为1->0->0->0。
代码:
package chapter_2_listproblem;
import java.util.Stack;
public class Problem_10_AddTwoLinkedLists {
public static class Node {
public int value;
public Node next;
public Node(int data) {
this.value = data;
}
}
public static Node addLists1(Node head1, Node head2) {
Stack<Integer> s1 = new Stack<Integer>();
Stack<Integer> s2 = new Stack<Integer>();
while (head1 != null) {
s1.push(head1.value);
head1 = head1.next;
}
while (head2 != null) {
s2.push(head2.value);
head2 = head2.next;
}
int ca = 0;
int n1 = 0;
int n2 = 0;
int n = 0;
Node node = null;
Node pre = null;
while (!s1.isEmpty() || !s2.isEmpty()) {
n1 = s1.isEmpty() ? 0 : s1.pop();
n2 = s2.isEmpty() ? 0 : s2.pop();
n = n1 + n2 + ca;
pre = node;
node = new Node(n % 10);
node.next = pre;
ca = n / 10;
}
if (ca == 1) {
pre = node;
node = new Node(1);
node.next = pre;
}
return node;
}
public static Node addLists2(Node head1, Node head2) {
head1 = reverseList(head1);
head2 = reverseList(head2);
int ca = 0;
int n1 = 0;
int n2 = 0;
int n = 0;
Node c1 = head1;
Node c2 = head2;
Node node = null;
Node pre = null;
while (c1 != null || c2 != null) {
n1 = c1 != null ? c1.value : 0;
n2 = c2 != null ? c2.value : 0;
n = n1 + n2 + ca;
pre = node;
node = new Node(n % 10);
node.next = pre;
ca = n / 10;
c1 = c1 != null ? c1.next : null;
c2 = c2 != null ? c2.next : null;
}
if (ca == 1) {
pre = node;
node = new Node(1);
node.next = pre;
}
reverseList(head1);
reverseList(head2);
return node;
}
public static Node reverseList(Node head) {
Node pre = null;
Node next = null;
while (head != null) {
next = head.next;
head.next = pre;
pre = head;
head = next;
}
return pre;
}
public static void printLinkedList(Node head) {
System.out.print("Linked List: ");
while (head != null) {
System.out.print(head.value + " ");
head = head.next;
}
System.out.println();
}
public static void main(String[] args) {
Node head1 = new Node(9);
head1.next = new Node(9);
head1.next.next = new Node(9);
Node head2 = new Node(1);
printLinkedList(head1);
printLinkedList(head2);
printLinkedList(addLists1(head1, head2));
printLinkedList(addLists2(head1, head2));
}
}
5. 两个单链表相交的一系列问题
题目描述:
在本题中,单链表可能有环也可能无环。给定两个单链表的头节点 head1 和 head2,这两个单链表可能相交也可能不相交。请实现一个函数,如果两个链表相交,请返回相交的第一个节点;如果不相交,返回 NULL。
代码:
package chapter_2_listproblem;
public class Problem_11_FindFirstIntersectNode {
public static class Node {
public int value;
public Node next;
public Node(int data) {
this.value = data;
}
}
public static Node getIntersectNode(Node head1, Node head2) {
if (head1 == null || head2 == null) {
return null;
}
Node loop1 = getLoopNode(head1);
Node loop2 = getLoopNode(head2);
if (loop1 == null && loop2 == null) {
return noLoop(head1, head2);
}
if (loop1 != null && loop2 != null) {
return bothLoop(head1, loop1, head2, loop2);
}
return null;
}
public static Node getLoopNode(Node head) {
if (head == null || head.next == null || head.next.next == null) {
return null;
}
Node n1 = head.next; // n1 -> slow
Node n2 = head.next.next; // n2 -> fast
while (n1 != n2) {
if (n2.next == null || n2.next.next == null) {
return null;
}
n2 = n2.next.next;
n1 = n1.next;
}
n2 = head; // n2 -> walk again from head
while (n1 != n2) {
n1 = n1.next;
n2 = n2.next;
}
return n1;
}
public static Node noLoop(Node head1, Node head2) {
if (head1 == null || head2 == null) {
return null;
}
Node cur1 = head1;
Node cur2 = head2;
int n = 0;
while (cur1.next != null) {
n++;
cur1 = cur1.next;
}
while (cur2.next != null) {
n--;
cur2 = cur2.next;
}
if (cur1 != cur2) {
return null;
}
cur1 = n > 0 ? head1 : head2;
cur2 = cur1 == head1 ? head2 : head1;
n = Math.abs(n);
while (n != 0) {
n--;
cur1 = cur1.next;
}
while (cur1 != cur2) {
cur1 = cur1.next;
cur2 = cur2.next;
}
return cur1;
}
public static Node bothLoop(Node head1, Node loop1, Node head2, Node loop2) {
Node cur1 = null;
Node cur2 = null;
if (loop1 == loop2) {
cur1 = head1;
cur2 = head2;
int n = 0;
while (cur1 != loop1) {
n++;
cur1 = cur1.next;
}
while (cur2 != loop2) {
n--;
cur2 = cur2.next;
}
cur1 = n > 0 ? head1 : head2;
cur2 = cur1 == head1 ? head2 : head1;
n = Math.abs(n);
while (n != 0) {
n--;
cur1 = cur1.next;
}
while (cur1 != cur2) {
cur1 = cur1.next;
cur2 = cur2.next;
}
return cur1;
} else {
cur1 = loop1.next;
while (cur1 != loop1) {
if (cur1 == loop2) {
return loop1;
}
cur1 = cur1.next;
}
return null;
}
}
public static void main(String[] args) {
// 1->2->3->4->5->6->7->null
Node head1 = new Node(1);
head1.next = new Node(2);
head1.next.next = new Node(3);
head1.next.next.next = new Node(4);
head1.next.next.next.next = new Node(5);
head1.next.next.next.next.next = new Node(6);
head1.next.next.next.next.next.next = new Node(7);
// 0->9->8->6->7->null
Node head2 = new Node(0);
head2.next = new Node(9);
head2.next.next = new Node(8);
head2.next.next.next = head1.next.next.next.next.next; // 8->6
System.out.println(getIntersectNode(head1, head2).value);
// 1->2->3->4->5->6->7->4...
head1 = new Node(1);
head1.next = new Node(2);
head1.next.next = new Node(3);
head1.next.next.next = new Node(4);
head1.next.next.next.next = new Node(5);
head1.next.next.next.next.next = new Node(6);
head1.next.next.next.next.next.next = new Node(7);
head1.next.next.next.next.next.next = head1.next.next.next; // 7->4
// 0->9->8->2...
head2 = new Node(0);
head2.next = new Node(9);
head2.next.next = new Node(8);
head2.next.next.next = head1.next; // 8->2
System.out.println(getIntersectNode(head1, head2).value);
// 0->9->8->6->4->5->6..
head2 = new Node(0);
head2.next = new Node(9);
head2.next.next = new Node(8);
head2.next.next.next = head1.next.next.next.next.next; // 8->6
System.out.println(getIntersectNode(head1, head2).value);
}
}
6. 将单链表的每K个节点之间逆序
题目描述:
给定一个单链表的头节点 head,实现一个调整单链表的函数,使得每K个节点之间逆序,如果最后不够K个节点一组,则不调整最后几个节点。
例如:
链表:1->2->3->4->5->6->7->8->NULL,K = 3.
调整后为:3->2->1->6->5->4->7->8->NULL。其中7、8不调整,因为不够一组。
代码:
package chapter_2_listproblem;
import java.util.Stack;
public class Problem_12_ConvertEveryKNodesInList {
public static class Node {
public int value;
public Node next;
public Node(int data) {
this.value = data;
}
}
public static Node reverseKNodes1(Node head, int K) {
if (K < 2) {
return head;
}
Stack<Node> stack = new Stack<Node>();
Node newHead = head;
Node cur = head;
Node pre = null;
Node next = null;
while (cur != null) {
next = cur.next;
stack.push(cur);
if (stack.size() == K) {
pre = resign1(stack, pre, next);
newHead = newHead == head ? cur : newHead;
}
cur = next;
}
return newHead;
}
public static Node resign1(Stack<Node> stack, Node left, Node right) {
Node cur = stack.pop();
if (left != null) {
left.next = cur;
}
Node next = null;
while (!stack.isEmpty()) {
next = stack.pop();
cur.next = next;
cur = next;
}
cur.next = right;
return cur;
}
public static Node reverseKNodes2(Node head, int K) {
if (K < 2) {
return head;
}
Node cur = head;
Node start = null;
Node pre = null;
Node next = null;
int count = 1;
while (cur != null) {
next = cur.next;
if (count == K) {
start = pre == null ? head : pre.next;
head = pre == null ? cur : head;
resign2(pre, start, cur, next);
pre = start;
count = 0;
}
count++;
cur = next;
}
return head;
}
public static void resign2(Node left, Node start, Node end, Node right) {
Node pre = start;
Node cur = start.next;
Node next = null;
while (cur != right) {
next = cur.next;
cur.next = pre;
pre = cur;
cur = next;
}
if (left != null) {
left.next = end;
}
start.next = right;
}
public static void printLinkedList(Node head) {
System.out.print("Linked List: ");
while (head != null) {
System.out.print(head.value + " ");
head = head.next;
}
System.out.println();
}
public static void main(String[] args) {
Node head = null;
int K = 3;
printLinkedList(head);
head = reverseKNodes1(head, K);
printLinkedList(head);
head = reverseKNodes2(head, K);
printLinkedList(head);
System.out.println("=======================");
head = new Node(1);
K = 3;
printLinkedList(head);
head = reverseKNodes1(head, K);
printLinkedList(head);
head = reverseKNodes2(head, K);
printLinkedList(head);
System.out.println("=======================");
head = new Node(1);
head.next = new Node(2);
K = 2;
printLinkedList(head);
head = reverseKNodes1(head, K);
printLinkedList(head);
head = reverseKNodes2(head, K);
printLinkedList(head);
System.out.println("=======================");
head = new Node(1);
head.next = new Node(2);
K = 3;
printLinkedList(head);
head = reverseKNodes1(head, K);
printLinkedList(head);
head = reverseKNodes2(head, K);
printLinkedList(head);
System.out.println("=======================");
head = new Node(1);
head.next = new Node(2);
head.next.next = new Node(3);
head.next.next.next = new Node(4);
K = 2;
printLinkedList(head);
head = reverseKNodes1(head, K);
printLinkedList(head);
head = reverseKNodes2(head, K);
printLinkedList(head);
System.out.println("=======================");
head = new Node(1);
head.next = new Node(2);
head.next.next = new Node(3);
head.next.next.next = new Node(4);
head.next.next.next.next = new Node(5);
head.next.next.next.next.next = new Node(6);
head.next.next.next.next.next.next = new Node(7);
head.next.next.next.next.next.next.next = new Node(8);
K = 3;
printLinkedList(head);
head = reverseKNodes1(head, K);
printLinkedList(head);
head = reverseKNodes2(head, K);
printLinkedList(head);
System.out.println("=======================");
}
}
7. 删除无序单链表中值重复出现的节点
题目描述:
给定一个无序单链表的头节点 head,删除其中值重复出现的节点。
例如:1->2->3->3->4->4->2->1->NULL,删除值重复的节点之后为1->2->3->4->NULL。
请按以下要求实现两种方法:
方法一:如果链表长度为 N,时间复杂度达到 O(N)。
方法二:额外空间复杂度为O(1)。
代码:
package chapter_2_listproblem;
import java.util.HashSet;
public class Problem_13_RemoveRepetition {
public static class Node {
public int value;
public Node next;
public Node(int data) {
this.value = data;
}
}
public static void removeRep1(Node head) {
if (head == null) {
return;
}
HashSet<Integer> set = new HashSet<Integer>();
Node pre = head;
Node cur = head.next;
set.add(head.value);
while (cur != null) {
if (set.contains(cur.value)) {
pre.next = cur.next;
} else {
set.add(cur.value);
pre = cur;
}
cur = cur.next;
}
}
public static void removeRep2(Node head) {
Node cur = head;
Node pre = null;
Node next = null;
while (cur != null) {
pre = cur;
next = cur.next;
while (next != null) {
if (cur.value == next.value) {
pre.next = next.next;
} else {
pre = next;
}
next = next.next;
}
cur = cur.next;
}
}
public static void printLinkedList(Node head) {
System.out.print("Linked List: ");
while (head != null) {
System.out.print(head.value + " ");
head = head.next;
}
System.out.println();
}
public static void main(String[] args) {
Node head = new Node(1);
head.next = new Node(2);
head.next.next = new Node(3);
head.next.next.next = new Node(3);
head.next.next.next.next = new Node(4);
head.next.next.next.next.next = new Node(4);
head.next.next.next.next.next.next = new Node(2);
head.next.next.next.next.next.next.next = new Node(1);
head.next.next.next.next.next.next.next.next = new Node(1);
removeRep1(head);
printLinkedList(head);
head = new Node(1);
head.next = new Node(1);
head.next.next = new Node(3);
head.next.next.next = new Node(3);
head.next.next.next.next = new Node(4);
head.next.next.next.next.next = new Node(4);
head.next.next.next.next.next.next = new Node(2);
head.next.next.next.next.next.next.next = new Node(1);
head.next.next.next.next.next.next.next.next = new Node(1);
removeRep2(head);
printLinkedList(head);
}
}
8. 在单链表中删除指定值的节点
题目描述:
给定一个链表的头节点 head 和一个整数 num,请实现函数将值为 num 的节点全部删除。
例如,链表为 1->2->3->4->NULL,num=3,链表调整后为:1->2->4->NULL。
代码:
package chapter_2_listproblem;
import java.util.Stack;
public class Problem_14_RemoveGivenValue {
public static class Node {
public int value;
public Node next;
public Node(int data) {
this.value = data;
}
}
public static Node removeValue1(Node head, int num) {
Stack<Node> stack = new Stack<Node>();
while (head != null) {
if (head.value != num) {
stack.push(head);
}
head = head.next;
}
while (!stack.isEmpty()) {
stack.peek().next = head;
head = stack.pop();
}
return head;
}
public static Node removeValue2(Node head, int num) {
while (head != null) {
if (head.value != num) {
break;
}
head = head.next;
}
Node pre = head;
Node cur = head;
while (cur != null) {
if (cur.value == num) {
pre.next = cur.next;
} else {
pre = cur;
}
cur = cur.next;
}
return head;
}
public static void printLinkedList(Node head) {
System.out.print("Linked List: ");
while (head != null) {
System.out.print(head.value + " ");
head = head.next;
}
System.out.println();
}
public static void main(String[] args) {
Node head = new Node(1);
head.next = new Node(1);
head.next.next = new Node(3);
head.next.next.next = new Node(3);
head.next.next.next.next = new Node(1);
head.next.next.next.next.next = new Node(2);
head.next.next.next.next.next.next = new Node(1);
head.next.next.next.next.next.next.next = new Node(1);
head = removeValue1(head, 1);
printLinkedList(head);
head = new Node(1);
head.next = new Node(1);
head.next.next = new Node(3);
head.next.next.next = new Node(3);
head.next.next.next.next = new Node(1);
head.next.next.next.next.next = new Node(2);
head.next.next.next.next.next.next = new Node(1);
head.next.next.next.next.next.next.next = new Node(1);
head = removeValue2(head, 1);
printLinkedList(head);
}
}
9. 将搜索二叉树转换成双向链表
题目描述:
对于二叉树的节点来说,有本身的值域,有指向左孩子和右孩子的两个指针;对双向链表的节点来说,有本身的值域,有指向上一个节点和下一个节点的指针。在结构上,两种结构有相似性,现有一棵搜索二叉树,请将其转为成一个有序的双向链表。
代码:
package chapter_2_listproblem;
import java.util.LinkedList;
import java.util.Queue;
public class Problem_15_BSTtoDoubleLinkedList {
public static class Node {
public int value;
public Node left;
public Node right;
public Node(int data) {
this.value = data;
}
}
public static Node convert1(Node head) {
Queue<Node> queue = new LinkedList<Node>();
inOrderToQueue(head, queue);
if (queue.isEmpty()) {
return head;
}
head = queue.poll();
Node pre = head;
pre.left = null;
Node cur = null;
while (!queue.isEmpty()) {
cur = queue.poll();
pre.right = cur;
cur.left = pre;
pre = cur;
}
pre.right = null;
return head;
}
public static void inOrderToQueue(Node head, Queue<Node> queue) {
if (head == null) {
return;
}
inOrderToQueue(head.left, queue);
queue.offer(head);
inOrderToQueue(head.right, queue);
}
public static class RetrunType {
public Node start;
public Node end;
public RetrunType(Node start, Node end) {
this.start = start;
this.end = end;
}
}
public static Node convert2(Node head) {
if (head == null) {
return null;
}
return process(head).start;
}
public static RetrunType process(Node head) {
if (head == null) {
return new RetrunType(null, null);
}
RetrunType leftList = process(head.left);
RetrunType rightList = process(head.right);
if (leftList.end != null) {
leftList.end.right = head;
}
head.left = leftList.end;
head.right = rightList.start;
if (rightList.start != null) {
rightList.start.left = head;
}
return new RetrunType(leftList.start != null ? leftList.start : head,
rightList.end != null ? rightList.end : head);
}
public static void printBSTInOrder(Node head) {
System.out.print("BST in-order: ");
if (head != null) {
inOrderPrint(head);
}
System.out.println();
}
public static void inOrderPrint(Node head) {
if (head == null) {
return;
}
inOrderPrint(head.left);
System.out.print(head.value + " ");
inOrderPrint(head.right);
}
public static void printDoubleLinkedList(Node head) {
System.out.print("Double Linked List: ");
Node end = null;
while (head != null) {
System.out.print(head.value + " ");
end = head;
head = head.right;
}
System.out.print("| ");
while (end != null) {
System.out.print(end.value + " ");
end = end.left;
}
System.out.println();
}
public static void main(String[] args) {
Node head = new Node(5);
head.left = new Node(2);
head.right = new Node(9);
head.left.left = new Node(1);
head.left.right = new Node(3);
head.left.right.right = new Node(4);
head.right.left = new Node(7);
head.right.right = new Node(10);
head.left.left = new Node(1);
head.right.left.left = new Node(6);
head.right.left.right = new Node(8);
printBSTInOrder(head);
head = convert1(head);
printDoubleLinkedList(head);
head = new Node(5);
head.left = new Node(2);
head.right = new Node(9);
head.left.left = new Node(1);
head.left.right = new Node(3);
head.left.right.right = new Node(4);
head.right.left = new Node(7);
head.right.right = new Node(10);
head.left.left = new Node(1);
head.right.left.left = new Node(6);
head.right.left.right = new Node(8);
printBSTInOrder(head);
head = convert2(head);
printDoubleLinkedList(head);
}
}
10. 单链表的选择排序
题目描述:
给定一个无序单链表的头节点 head,实现单链表的选择排序。
要求:额外的空间复杂读为 O(1)。
代码:
package chapter_2_listproblem;
public class Problem_16_ListSelectionSort {
public static class Node {
public int value;
public Node next;
public Node(int data) {
this.value = data;
}
}
public static Node selectionSort(Node head) {
Node tail = null; // sorted part tail
Node cur = head; // unsorted part head
Node smallPre = null; // previous node of the smallest node
Node small = null; // smallest node
while (cur != null) {
small = cur;
smallPre = getSmallestPreNode(cur);
if (smallPre != null) {
small = smallPre.next;
smallPre.next = small.next;
}
cur = cur == small ? cur.next : cur;
if (tail == null) {
head = small;
} else {
tail.next = small;
}
tail = small;
}
return head;
}
public static Node getSmallestPreNode(Node head) {
Node smallPre = null;
Node small = head;
Node pre = head;
Node cur = head.next;
while (cur != null) {
if (cur.value < small.value) {
smallPre = pre;
small = cur;
}
pre = cur;
cur = cur.next;
}
return smallPre;
}
public static void printLinkedList(Node head) {
System.out.print("Linked List: ");
while (head != null) {
System.out.print(head.value + " ");
head = head.next;
}
System.out.println();
}
public static void main(String[] args) {
Node head = null;
head = selectionSort(head);
printLinkedList(head);
head = new Node(1);
head = selectionSort(head);
printLinkedList(head);
head = new Node(1);
head.next = new Node(2);
head = selectionSort(head);
printLinkedList(head);
head = new Node(2);
head.next = new Node(1);
head = selectionSort(head);
printLinkedList(head);
head = new Node(1);
head.next = new Node(2);
head.next.next = new Node(3);
head = selectionSort(head);
printLinkedList(head);
head = new Node(1);
head.next = new Node(3);
head.next.next = new Node(2);
head = selectionSort(head);
printLinkedList(head);
head = new Node(2);
head.next = new Node(1);
head.next.next = new Node(3);
head = selectionSort(head);
printLinkedList(head);
head = new Node(2);
head.next = new Node(3);
head.next.next = new Node(1);
head = selectionSort(head);
printLinkedList(head);
head = new Node(3);
head.next = new Node(1);
head.next.next = new Node(2);
head = selectionSort(head);
printLinkedList(head);
head = new Node(3);
head.next = new Node(2);
head.next.next = new Node(1);
head = selectionSort(head);
printLinkedList(head);
head = new Node(3);
head.next = new Node(1);
head.next.next = new Node(4);
head.next.next.next = new Node(2);
head = selectionSort(head);
printLinkedList(head);
}
}
11. 一种怪异的节点删除方式
题目描述:
链表节点值类型为 int 型,给定一个链表中的节点 node,但不给定整个链表的头节点。如何在链表中删除 node?请实现这个函数,并分析这么做会出现那些问题。
要求:额外的空间复杂读为 O(1)。
代码:
package chapter_2_listproblem;
public class Problem_17_RemoveNodeWired {
public static class Node {
public int value;
public Node next;
public Node(int data) {
this.value = data;
}
}
public static void removeNodeWired(Node node) {
if (node == null) {
return;
}
Node next = node.next;
if (next == null) {
throw new RuntimeException("can not remove last node.");
}
node.value = next.value;
node.next = next.next;
}
public static void printLinkedList(Node head) {
System.out.print("Linked List: ");
while (head != null) {
System.out.print(head.value + " ");
head = head.next;
}
System.out.println();
}
public static void main(String[] args) {
Node head = new Node(1);
head.next = new Node(2);
head.next.next = new Node(3);
Node node = head;
printLinkedList(head);
removeNodeWired(node);
printLinkedList(head);
head = new Node(1);
head.next = new Node(2);
head.next.next = new Node(3);
node = head.next;
printLinkedList(head);
removeNodeWired(node);
printLinkedList(head);
// head = new Node(1);
// head.next = new Node(2);
// head.next.next = new Node(3);
// node = head.next.next;
// printLinkedList(head);
// removeNodeWired(node);
// printLinkedList(head);
}
}
12. 合并两个有序的单链表
题目描述:
给定两个有序单链表的头节点 head1 和 head2,请合并两个有序链表,合并后的链表依然有序,并返回合并后链表的头节点。
例如:
0->2->3->7->NULL
1->3->5->7->9->NULL
合并后的链表为:0->1->2->3->3->5->7->7->9->NULL
代码:
package chapter_2_listproblem;
public class Problem_18_InsertNumToCircularList {
public static class Node {
public int value;
public Node next;
public Node(int data) {
this.value = data;
}
}
public static Node insertNum(Node head, int num) {
Node node = new Node(num);
if (head == null) {
node.next = node;
return node;
}
Node pre = head;
Node cur = head.next;
while (cur != head) {
if (pre.value <= num && cur.value >= num) {
break;
}
pre = cur;
cur = cur.next;
}
pre.next = node;
node.next = cur;
return head.value < num ? head : node;
}
public static void printCircularList(Node head) {
if (head == null) {
return;
}
System.out.print("Circular List: " + head.value + " ");
Node cur = head.next;
while (cur != head) {
System.out.print(cur.value + " ");
cur = cur.next;
}
System.out.println("-> " + head.value);
}
public static void main(String[] args) {
Node head = null;
head = insertNum(head, 2);
printCircularList(head);
head = insertNum(head, 1);
printCircularList(head);
head = insertNum(head, 4);
printCircularList(head);
head = insertNum(head, 3);
printCircularList(head);
head = insertNum(head, 5);
printCircularList(head);
head = insertNum(head, 0);
printCircularList(head);
}
}
13. 向有序的环形单链表中插入新节点
题目描述:
一个环形单链表从头节点 head 开始不降序,同时由最后的节点指向头节点。给定这样的一个环形单链表的头节点 head 和一个整数 num,请生成节点值为 num 的新节点,并插入到这个环形链表中,保证调整后的链表依然有序。
代码:
package chapter_2_listproblem;
public class Problem_18_InsertNumToCircularList {
public static class Node {
public int value;
public Node next;
public Node(int data) {
this.value = data;
}
}
public static Node insertNum(Node head, int num) {
Node node = new Node(num);
if (head == null) {
node.next = node;
return node;
}
Node pre = head;
Node cur = head.next;
while (cur != head) {
if (pre.value <= num && cur.value >= num) {
break;
}
pre = cur;
cur = cur.next;
}
pre.next = node;
node.next = cur;
return head.value < num ? head : node;
}
public static void printCircularList(Node head) {
if (head == null) {
return;
}
System.out.print("Circular List: " + head.value + " ");
Node cur = head.next;
while (cur != head) {
System.out.print(cur.value + " ");
cur = cur.next;
}
System.out.println("-> " + head.value);
}
public static void main(String[] args) {
Node head = null;
head = insertNum(head, 2);
printCircularList(head);
head = insertNum(head, 1);
printCircularList(head);
head = insertNum(head, 4);
printCircularList(head);
head = insertNum(head, 3);
printCircularList(head);
head = insertNum(head, 5);
printCircularList(head);
head = insertNum(head, 0);
printCircularList(head);
}
}
14. 按照左右半区的方式重新组合单链表
题目描述:
给定一个单链表的头节点 head,链表长度为 N,如果 N 为偶数那么前 N/2 个节点算作左半区,后 N/2 个节点算作右半区;如果 N 为奇数,那么前 N/2 个节点算作左半区,后 N/2+1 个节点算作右半区。左半区从左到右依次记为 L1->L2->…,右半区从左到右依次记为 R1->R2->…,请将链表调整为 L1->R1->L2->R2->…的形式。
代码:
package chapter_2_listproblem;
public class Problem_20_RelocateLinkedList {
public static class Node {
public int value;
public Node next;
public Node(int value) {
this.value = value;
}
}
public static void relocate(Node head) {
if (head == null || head.next == null) {
return;
}
Node mid = head;
Node right = head.next;
while (right.next != null && right.next.next != null) {
mid = mid.next;
right = right.next.next;
}
right = mid.next;
mid.next = null;
mergeLR(head, right);
}
public static void mergeLR(Node left, Node right) {
Node next = null;
while (left.next != null) {
next = right.next;
right.next = left.next;
left.next = right;
left = right.next;
right = next;
}
left.next = right;
}
public static void printLinkedList(Node head) {
System.out.print("Linked List: ");
while (head != null) {
System.out.print(head.value + " ");
head = head.next;
}
System.out.println();
}
public static void main(String[] args) {
Node head = null;
relocate(head);
printLinkedList(head);
head = new Node(1);
relocate(head);
printLinkedList(head);
head = new Node(1);
head.next = new Node(2);
relocate(head);
printLinkedList(head);
head = new Node(1);
head.next = new Node(2);
head.next.next = new Node(3);
relocate(head);
printLinkedList(head);
head = new Node(1);
head.next = new Node(2);
head.next.next = new Node(3);
head.next.next.next = new Node(4);
relocate(head);
printLinkedList(head);
head = new Node(1);
head.next = new Node(2);
head.next.next = new Node(3);
head.next.next.next = new Node(4);
head.next.next.next.next = new Node(5);
relocate(head);
printLinkedList(head);
head = new Node(1);
head.next = new Node(2);
head.next.next = new Node(3);
head.next.next.next = new Node(4);
head.next.next.next.next = new Node(5);
head.next.next.next.next.next = new Node(6);
relocate(head);
printLinkedList(head);
head = new Node(1);
head.next = new Node(2);
head.next.next = new Node(3);
head.next.next.next = new Node(4);
head.next.next.next.next = new Node(5);
head.next.next.next.next.next = new Node(6);
head.next.next.next.next.next.next = new Node(7);
relocate(head);
printLinkedList(head);
}
}