慕课网liuyubobobo老师课程学习笔记---part4:链表和递归(递归很重要!)

这篇博客主要讲解了如何使用递归解决LeetCode第203题,探讨了递归的运行机制、调试方法,并介绍了链表的相关概念,包括数组链表和循环链表。
摘要由CSDN通过智能技术生成

1、LeetCode第203题解析

移除链表元素

  题目描述:

删除链表中等于给定值 val 的所有节点。

示例:
	输入: 1->2->6->3->4->5->6, val = 6
	输出: 1->2->3->4->5

  代码如下:

package com.lkj.Problem203;

//第203:移除链表元素
/* 题目描述
    删除链表中等于给定值 val 的所有节点。

    示例:

    输入: 1->2->6->3->4->5->6, val = 6
    输出: 1->2->3->4->5
 */

/**  解题模板:利用以下结点构造链表解题(在LeetCode中不需要创建这个结点类,但是我们自己在IDE中测试的时候需要添加这个结点类)
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode(int x) { val = x; }
 * }
 */
public class LCTest203
{
   
    /**
     * 解析:这题实际上是对链表中的元素进行删除,删除结点需要找到该结点在链表中的上一个结点
     * 我们可以采用虚拟头结点的方式进行删除,这样就能找到所有结点的上一个结点。
     * 或者是分第一个结点和其他结点的方式进行分情况删除。
     */

    //首先,我们采用不涉及头结点的方式进行删除,这就要分情况删除:分删除第一个结点和删除其他结点的情况
    public ListNode removeElements1(ListNode head, int val)
    {
   
        /*
        首先,我们先判断第一个结点,如果这个结点的值符合val,就对他进行删除。但是有可能开头连续几个都是满足val,
        因此,我们必须循环判断。但是,有可能整个链表都满足val,删除到最后链表为空,我们还进行 head.val = val
        的判断就会出现空指针异常,因此我们还需要判断head是否为null,既链表是否为空。
        这样判断,就把一开始链表为空的情况也考虑进去。
         */

        //当链表不为空 head!=null,且head.val = val时,进行删除
        while (head != null && head.val == val)
        {
   
            //没有前一个结点的删除方法
            ListNode delNode = head;
            head = head.next;
            delNode.next = null;
        }
        //如果一开始链表就为null,就会不会进入循环;当链表头的val删除完毕后,就会跳出循环。
        //如果一开始链表就为null,或者整个链表都是val,整个链表被删除,那么此时head=null,我们直接返回head或者null
        if (head == null)
            return head;//返回null与返回head是相同的

        //当链表不为null,且开头不为val,对链表除开头外其他元素进行循环判断
        ListNode pre = head;//创建一个指针指向链表的第一个结点,同时可以用pre代表这个结点(这个结点的值不为val)
        while (pre.next != null)
        {
   
            //如果链表的下一个结点不为null,循环判断。
            // 如果下一个结点的值=val,那么就删除它,下下个结点就变成下一个结点,继续判断下一个结点值是否=val(此时不能向后移动。因为我们不知道之前下下个结点值是否为val)
            if (pre.next.val == val)
            {
   
                //有前一个结点的删除方法
                ListNode delNode = pre.next;
                pre.next = delNode.next;
                delNode.next = null;               

            }
            else
            {
   
                //如果下一个结点的值 != val,我们将当前结点后移一位
                pre = pre.next;
            }
        }

        return head;//最后,将删除val完毕的链表的第一个结点返回
    }

    //对上面方法进行简化
    public ListNode removeElements2(ListNode head, int val)
    {
   
        while (head != null && head.val == val)
        {
   
            /**
             * 如果我们不考虑前面说的 Loitering Object ,那么我们对于开头值是val的结点,可以不进行删除,
             * 而是直接将head移动到下一个结点。其实此时原来结点中的值还存在于内存中,但是LeetCode中运行完
             * 之后会将内存中的值全部释放,因此没什么关系
             */
            head = head.next;
        }
        if (head == null)
            return head;

        ListNode pre = head;
        while (pre.next != null)
        {
   
            if (pre.next.val == val)
            {
   
                /**
                 * 这里同样,如果不考虑Loitering Object,我们不需要将这个结点的元素删除。
                 * 直接将pre.next指定为pre.next.next,直接跳过下一个结点到下下个结点即可.
                 * 这样后面下一个结点的内存就会被自动回收
                 */
                pre.next = pre.next.next;
            }
            else
            {
   
                pre = pre.next;
            }
        }
    }

    //使用头结点进行删除(方便很多,因为所有结点都可以使用前一个结点进行删除)
    public ListNode removeElements3(ListNode head, int val)
    {
   
        ListNode dummyNode = new ListNode(-1);
        dummyNode.next = head;//创建一个头结点,值为-1,指向链表第一个结点

        ListNode pre = dummyNode;//创建前一个结点指向头结点(创建前一个才能将这个结点后移,而dummyNode不能直接后移)

        while (pre.next != null)
        {
   
            if(pre.next.val == val)
            {
   
//                ListNode delNode = pre.next;
//                pre.next = delNode.next;
//                delNode.next = null;
                pre.next = pre.next.next;
            }
            else
            {
   
                pre = pre.next;
            }
        }

        //最后我们要返回链表第一个结点。那么dummyNode的下一个结点指的结点链表第一个结点,直接返回dummyNode.next即可
        /*
        不能返回head,因为我们一直在改变的是dummyHead.next的值,虽然链表中满足条件的元素被删除了,但是head这个指针仍然指向原来链表的第一个结点,
        因为我们一直没有改变head指针的指向。如果原来链表的第一个结点的值满足,那么这个结点被dummyNode.next删除了,
        它不存在于链表中,但是指针head仍然指向这个结点,那么返回head就会返回一个链表中不存在的结点,而不是链表的第一个结点!
         */
        
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值