《程序员代码面试指南》第二章链表问题下

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接: https://blog.csdn.net/weixin_43928720/article/details/101170788

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);
	}
}

猜你喜欢

转载自blog.csdn.net/weixin_43928720/article/details/101170788
今日推荐