题目一:O(1)时间删除链表节点。
给定单向链表的头指针head和一个节点指针,定义一个函数在O(1)时间删除该节点。
测试用例:
1. 功能测试:从有多个节点的链表中分别删除头结点、中间节点、尾节点。
2. 边界测试:从只有一个节点的链表中删除节点。
3. 负面测试:输入的头结点为空;输入的要删除的节点为空。
思路一:常规做法,时间复杂度为 O(n)
直接从头到尾遍历找到要删除节点的前一个节点,然后把这一个节点的指针直接指向要删除节点的下一个节点。因为要遍历链表,所以时间复杂度为O(n)。
思路二:利用单向链表的特点,时间复杂度为O(1)
单向链表可以在O(1)时间内直接找到要删除节点的下一个节点,所以我们可以把这一个节点的内容复制到要删除的节点覆盖掉原有的内容,再把这一个节点删除,这样因为不用遍历链表,所以时间复杂度为O(1)。
不过要考虑两个特殊情况:第一个是要删除链表中唯一的节点,直接把头结点设置为空就行;第二情况是要删除的节点位于尾节点,这时候因为没有下一个节点了,所以要用常规做法从头到尾遍历,找到倒数第二个节点,然后再把尾节点删除。
public class test_eighteen {
public void deleteNode(ListNode Head, ListNode ToBeDeleted){
if(Head == null || ToBeDeleted == null)return;
//要删除的节点不是尾节点
if(ToBeDeleted.next != null){
ToBeDeleted.val = ToBeDeleted.next.val;
ToBeDeleted.next = ToBeDeleted.next .next ;
}
//链表只有一个节点,删除头结点
else if(Head == ToBeDeleted){
Head = null;
}
//链表有多个节点,删除尾节点(需要从头到尾遍历找到要删除节点的前一个节点)
else{
ListNode temp = Head;
while(temp.next != ToBeDeleted){
temp = temp.next;
}
temp.next = null;
ToBeDeleted = null;
}
}
}
题目二:删除链表中重复的节点。
测试用例:
1. 功能测试:重复节点分别位于链表的头部、中部、尾部。
2. 边界测试:链表没有重复节点;链表全部都是重复节点。
3. 负面测试:输入的头节点为空。
思路:
这道题可以用递归的方法来做比较简洁,从头到尾遍历链表,判断当前遍历到的节点是不是重复节点(与下一个节点值相不相等),若是重复节点就要遍历找到第一个与当前节点值不相等的节点,从这个节点重新判断是不是重复节点(调用递归函数);若当前节点不是重复节点,则把这个不重复的节点保留输出,然后从下一个节点开始再一个判断(再调用递归函数)。
public ListNode deleteDupliction(ListNode head){
if(head == null || head.next == null)return head; //只有0个或1个节点,直接return
//从头到尾开始遍历
if(head.val == head.next.val){ //如果当前节点是重复节点
ListNode temp = head.next;
while(temp != null && temp.val == head.val){ //找到第一个与当前节点值不相等的节点
temp = temp.next;
}
return deleteDupliction(temp); //从这个节点开始递归
}else{ //当前节点不是重复节点
head.next = deleteDupliction(head.next); //从下一个节点开始递归
return head; //返回的是当前节点,因为它不是重复节点
}
}