数据结构之链表的删除

目录

第一题:删除链表中的节点(leetcode第237题)(简单)

第二题:删除链表中重复的元素 I(leetcode第82题)(简单)

第三题:删除链表中的重复元素II(leetcode第82题)(中等)

第四题:删除链表中倒数第N个节点(leetcode第19题)(中等)

第五题:移除链表元素(leetcode第203题)(简单)


第一题:删除链表中的节点(leetcode第237题)(简单)

思路分析

1:因为题目中只给定了要删除的节点,并没有给出链表的头结点,所以无法通过遍历查询到待删除节点的上一个节点,然后执行删除操作

2:对此,我们利用给定的待删除节点的信息,将待删除节点的下一个节点的值付给待删除的节点,这样就可以将待删除节点的next指针域指向下一个节点的下一个,从而实现删除操作

class Solution {
    public void deleteNode(ListNode node) {
        if(node==null){
            return;
        }
        node.val=node.next.val;
        node.next=node.next.next;
        
    }
}

第二题:删除链表中重复的元素 I(leetcode第82题)(简单)

思路分析:

1:由于给定的链表是排好序的,因此重复的元素在链表中出现的位置是连续的,因此我们只需要对链表进行一次遍历,就可以删除重复的元素。定义一个辅助节点temp用于遍历

2:当我们遍历到链表的最后一个节点时temp.next 为空节点,如果不加以判断,访问 temp.next 对应的元素会产生运行错误。

3: 当遍历到两个节点值相同时,执行删除操作,注意此处要用else将节点后移

class Solution {
    public ListNode deleteDuplicates(ListNode head) {
        if(head==null){
            return null;
        }
        ListNode temp=head;
        while(temp!=null&&temp.next!=null){
        if(temp.val==temp.next.val){
            temp.next=temp.next.next;
        }else{
            temp=temp.next;
        }
        
    }
     return head;
    }
}

第三题:删除链表中的重复元素II(leetcode第82题)(中等)

思路分析:

1:这道题的重点在于要删除所有相同的节点,所以我们不仅要有待删除的节点,但删除节点的下一个节点,还要有待删除节点的前一个节点

2:我们要定义一个头结点的前驱结点,让用于遍历链表的指针指向头结点的前驱节点preNode

class Solution {
    public ListNode deleteDuplicates(ListNode head) {
        if (head == null) {
            return head;
        }
        
        ListNode preNode= new ListNode(0, head);

        ListNode cur = preNode;
        while (cur.next != null && cur.next.next != null) {
            if (cur.next.val == cur.next.next.val) {
                int x = cur.next.val;
                while (cur.next != null && cur.next.val == x) {
                    cur.next = cur.next.next;
                }
            } else {
                cur = cur.next;
            }
        }

        return preNode.next;
    }
}

第四题:删除链表中倒数第N个节点(leetcode第19题)(中等)

单链表插入,删除都需要考虑头节点,当寻找前驱节点时由于头节点不存在前驱节点,需要另外考虑,此时引入虚拟头节点,虚拟头节点不存储具体元素,不考虑头结点是否空,头节点一定存在,则所有节点都有前驱节点

思略分析1双指针的解法

1:定义快指针fast,慢指针slow定义一个头结点的前一个节点preNode,慢指针指向前驱节点preNode,快指针指向头结点head,

2:链表的倒数第N个节点说明要让快指针先移动n次,慢指针不动

3:当快指针移动到第n个节点位置时,让快慢双指针同时移动,当快指针移动到链表尾时,此时慢指正刚好移动到待删除节点的前一个节点,执行删除操作

4: 定义的时候,如果将慢指针快指针都指向头结点,当返回head的时候,输出的结果就是1 2 3 4而不是1 2 3 5

图解如下:

class Solution {
    public ListNode removeNthFromEnd(ListNode head, int n) {
        if(head==null){
            return null;
        }
       //定义头结点的前驱节点
        ListNode preNode=new ListNode(0);
        ListNode fast=head;
        ListNode slow=preNode;
        slow.next=head;
       //让快指针先行移动到第n个节点的位置
        for(int i=0;i<n;i++){
            fast=fast.next;
        }
       //快慢双指针同时移动
        while(fast!=null){
            fast=fast.next;
            slow=slow.next;
        }
       //此时慢指针刚好移动到待删除节点的前一个节点
        slow.next=slow.next.next;
        return preNode.next;
    }
}

思路分析2:哈希表的解法

1:定义一个哈希表,将链表中的所有节点信息存入哈希表中map.put()方法

2:取出待删除节点,注意下标从0开始map.get()方法执行,判断待删除的节点是否为空,如果空则返回null

3:如果待删除的节点不为空,就判断待删除的节点是否为头结点,如果是头结点,则直接返回头结点的下一个节点

class Solution {
    public ListNode removeNthFromEnd(ListNode head, int n) {
        if(head==null){
            return null;
        }
        ListNode temp=head;
        int count=0;
        HashMap<Integer,ListNode> hashMap=new HashMap<>();
        while(temp!=null){
            //哈希表的下标从0开始
            hashMap.put(count,temp);
            count++;
            temp=temp.next;
        }
        //从哈希表中取出要删除的元素
        ListNode deleteNode=hashMap.get(count-n);
        if(deleteNode!=null){
            //如果要删除的节点正好是头结点,则直接返回头结点的下一个节点
            if(deleteNode==head){
                return head.next;
            }else{
                //定义要删除节点的前驱节点preNode,小标从0开始所以要减一
                ListNode preNode=hashMap.get(count-n-1);
                preNode.next=deleteNode.next;
            }
           
        }
         return head;
}
}

第五题:移除链表元素(leetcode第203题)(简单)

 思路分析1(虚拟头结点法):

1:定义一个虚拟头结点,temp,temp指向链表的头结点(即链表的第一个节点)。定义一个指针curNode指向虚拟头结点

2:遍历链表,当指向虚拟头结点的下一个节点为空时退出循环

3:最终返回虚拟头结点的下一个节点

class Solution {
    public ListNode removeElements(ListNode head, int val) {
        //先判断头结点是否为空
        if(head==null){
            return null;
        }
        //定义一个虚拟头结点
        ListNode temp=new ListNode(0);
        //虚拟头结点指向链表中第一个节点
        temp.next=head;
        //定义一个当前指针指向虚拟头结点,用于遍历操作
        ListNode curNode=temp;
        while(curNode.next!=null){
            if(curNode.next.val==val){
                curNode.next=curNode.next.next;
            }
            else{
                curNode=curNode.next;
            }
        }
        return temp.next;
    }
}

思路分析2(递归解法):

class Solution {
    public ListNode removeElements(ListNode head, int val) {   
        if(head==null){
            return null;
        }
        if(head.val!=val){
            head.next = removeElements(head.next,val);
            return head;
        }else{
            head=removeElements(head.next,val);
            return head;
        }
    }
}

  • 1
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值