1. 题目 :移除链表元素
给你一个链表的头节点 head 和一个整数 val ,请你删除链表中所有满足 Node.val == val 的节点,并返回 新的头节点 。
力扣
1.2 分析
1.2.1 这里没啥好分析的,就是查找是否相同的节点元素,但是需要注意要保存前一个节点的位置,然后和删除节点的后一个位置建立联系。
public ListNode removeElements(ListNode head, int val) {
ListNode res =new ListNode(0);
res.next = head;
ListNode cur = res;
while(cur.next!=null){
if(cur.next.val == val){
cur.next = cur.next.next;
}else{
cur =cur.next;
}
}
return res.next;
}
运行截图
时间复杂度:O(n) 遍历了一次链表
空间复杂度: O(1)
2. 题目:删除链表的倒数第 N 个结点
给你一个链表,删除链表的倒数第 n 个结点,并且返回链表的头结点。
力扣
2.1 分析
2.1.1 使用快慢指针,倒数第n的节点,就保持快慢指针之间相差n个节点,当快指针的next走到null的时候,这时候就是删除节点的前一个节点位置,然后指向删除节点的后一个节点。
public ListNode removeNthFromEnd(ListNode head, int n) {
ListNode slow = head;
ListNode fast = head;
// 快指针先走n步
while(n>0){
fast = fast.next;
n--;
}
// 防止是头节点
if(fast == null){
return head.next;
}
// 同时移动
while(fast.next!=null){
slow = slow.next;
fast = fast.next;
}
// 删除元素
slow.next = slow.next.next;
return head;
}
运行截图:
时间复杂度:O(n)遍历一次链表
空间复杂度:O(1)
总结:看一看见快慢指针速度还是可以的,不过尤其需要注意里面需要判断快指针是否为空的情况,这个时候意味着删除的就是头节点。
2.1.2 使用链表长度,通过正向找到节点的前一个节点的位置,然后指向删除节点的后一个节点。
public ListNode removeNthFromEnd(ListNode head, int n) {
ListNode sentail = new ListNode(0);
sentail.next = head;
ListNode currentNode =head;
ListNode temp = sentail;
// 计算长度
int length = 0;
while(currentNode!=null){
currentNode = currentNode.next;
length++;
}
// 移动第length-n-1元素位置
for(int i=0;i<length-n;i++){
temp = temp.next;
}
// 删除
temp.next = temp.next.next;
return sentail.next;
}
运行截图:
时间复杂度: O(n) 第一次遍历链表 O(n)第二次遍历部分链表O(k)k表示删除节点元素的位置,总体是O(n)
空间复杂度: O(1)
总结:我没想到的是内存消耗比快慢指针的还要小。
3. 删除排序链表中的重复元素
3.1 分析
3.1.1 先定位到当前节点,判断前后节点的值是否一样,一样就跳过第二个节点,否则正常向后遍历
public ListNode deleteDuplicates(ListNode head) {
if(head==null) return null;
ListNode currentNode = head;
while(currentNode.next!=null){
if(currentNode.val == currentNode.next.val){
currentNode.next = currentNode.next.next;
}else{
currentNode = currentNode.next;
}
}
return head;
}
运行截图:
时间复杂度:O(n)
空间复杂度: O(1)
总结:每次执行这种需要下一个节点的,记住需要判断头节点是否为空
4. 删除排序链表中的重复元素 II
给定一个已排序的链表的头 head , 删除原始链表中所有重复数字的节点,只留下不同的数字 。返回 已排序的链表 。
力扣
4.1 分析
4.1.1 发现这一题和上面的题目一样,但是i这一题不需要重复数据而是都删除。
public ListNode deleteDuplicates(ListNode head) {
if(head == null) return null;
ListNode sentail = new ListNode(0);
sentail.next = head;
ListNode current = sentail;
// 下一个节点和下下一个节点都不为空
while(current.next!=null && current.next.next !=null){
// 判断下个节点和下下节点是否值一致
if(current.next.val == current.next.next.val){
// 保存相同的值
int x =current.next.val;
// 当前节点的下一个值不为空,值等于x,跳过当前节点
while(current.next!=null && current.next.val == x){
current.next = current.next.next;
}
}else{
current = current.next;
}
}
return sentail.next;
}
运行截图
时间复杂度:O(n)
空间复杂度:O(n)
总结:原本以为很贱的,但是实际操作发现中间有些步骤还是有点难以考虑到,比如需要记录下下一个节点和下下节点的共同值,然后判断当前的下一个节点是否是这个共同值,是的话就跳过,比第三题多了一点限制条件,一开始不理解为什么要先记录共同值,现在了解了。
总结
删除链表节点这一块核心是需要找到当前删除节点的前后关系的节点,后两题目也是差不多意思,只不过第四题需要先将值先保存,判断下一个和下下一个节点关系。