题目:给定单向链表的头指针和一个节点指针,定义一个函数在
#card=math&code=O%281%29) 时间内删除该节点。
常规我们删除节点是从头节点开始遍历,找到要删除的节点,然后删除它。之所以要从头结点开始,是因为我们要找到该节点的前一个节点,然后才能删除该节点,有如下链表
比如我们要删除节点 3,这个时候我们必须找到它的前一个节点 2,将节点 2 的下一个指针指向节点 3 的下一个节点,如下
但是从头结点开始查找的话,它的时间复杂度就是 #card=math&code=O%28n%29),达不到题目所要求的
#card=math&code=O%281%29) 的时间复杂度,这个时候我们就要另辟蹊径了。还是以删除节点
3 为例,这个时候可以将它下一个节点的值覆盖要被删除节点的值,即用 4 覆盖 3,然后删除节点 4,因为我们知道节点 4 的前一个节点(即给定的要删除的节点),所以可以将节点 4 删除,如下
这时我们不用从头结点进行遍历,所需要的复杂度是 #card=math&code=O%281%29)。
但是事情到这里还没有完成,如果要删除的节点是最后一个节点呢? 这个时候它没有下一个节点,我们就不得不从头结点开始遍历来删除这个节点了,这个时候就得知道它的前一个节点。这里又要考虑一种情况,因为要知道尾结点的前一个节点,如果链表只有一个元素的话,尾结点就没有前一个节点,这种情况要做特殊处理。代码如下:
public class DeleteNode {private static class ListNode {ListNode next;int value;public ListNode(int value) {this.value = value;this.next = null;}}public static ListNode deleteNode(ListNode root, ListNode toBeDeletedNode) {if (root == null || toBeDeletedNode == null) {return root;}// 如果不是尾结点if (toBeDeletedNode.next != null) {// 将后面节点的值覆盖要删除的节点的值toBeDeletedNode.value = toBeDeletedNode.next.value;// 删除下一个节点ListNode deleteNext = toBeDeletedNode.next;toBeDeletedNode.next = deleteNext.next;deleteNext = null;} else {// 被删除的节点是尾结点ListNode cur = root;// 同时被删除的节点也是头结点,即只有一个元素if (cur == toBeDeletedNode) {root = null;toBeDeletedNode = null;return root;}// 从头结点遍历找到前一个节点while(cur.next != toBeDeletedNode) {cur = cur.next;}cur.next = null;toBeDeletedNode = null;}return root;}// 打印链表的方法public static void printList(ListNode root) {while (root != null) {if (root.next != null) {System.out.print(root.value + "->");} else {System.out.println(root.value);}root = root.next;}}// 测试代码public static void main(String[] args) {ListNode root = new ListNode(1);root.next = new ListNode(2);root.next.next = new ListNode(3);root.next.next.next = new ListNode(4);root.next.next.next.next = new ListNode(5);printList(root); // 1->2->3->4->5root = deleteNode(root, root.next.next.next.next);printList(root); // 1->2->3->4root = deleteNode(root, root);printList(root); // 2->3->4root = deleteNode(root, root.next);printList(root); // 2->4root = deleteNode(root, root.next);printList(root); // 2root = deleteNode(root, root);printList(root); //}}
题目:在一个排序的链表中,如何删除重复的节点?
这道题仔细一想的话非常简单,因为这个链表是有序的,这就意味着重复的节点是连在一起的,所以我们只要比较当前节点与下一个节点的值是否相同,如果相同,则删除下一个节点,如果不同则移动当前节点到下一个节点,代码如下:
public class DeleteDuplicationNode {private static class ListNode {ListNode next;int value;public ListNode(int value) {this.value = value;this.next = null;}}public static void deleteDuplicationNode(ListNode root) {if (root == null) {return;}ListNode cur = root;while(cur.next != null) {// 如果当前节点的值与下一个节点的值相同,删除下一个节点if (cur.value == cur.next.value) {ListNode curNext = cur.next;cur.next = curNext.next;curNext = null;} else {// 否则移动当前节点cur = cur.next;}}}// 打印链表public static void printList(ListNode root) {while (root != null) {if (root.next != null) {System.out.print(root.value + "->");} else {System.out.println(root.value);}root = root.next;}}public static void main(String[] args) {ListNode root = new ListNode(1);root.next = new ListNode(1);root.next.next = new ListNode(2);root.next.next.next = new ListNode(2);root.next.next.next.next = new ListNode(2);root.next.next.next.next.next = new ListNode(3);printList(root); // 1->1->2->2->2->3deleteDuplicationNode(root); // 1->2->3printList(root);}}
