代码随想录算法训练营Day3 | 203.移除链表元素、707.设计链表、59.螺旋矩阵II

2023-12-17

LeetCode 203 移除链表元素

本题思路:就是常规的移除链表中的元素的操作。 需要注意的点:

  1. 头节点 head.val = val 的情况的处理 ,如果 head.val = val , 就要继续往后 head = head.next ,因此我们要遍历到第一个 head.val != val 的节点
  2. 如果遍历到最后,所有的节点的值都不等于 val,此时就直接返回 head;
  3. 如果遍历到最后,链表中还有元素。此时就开始做判断
class Solution {
    public ListNode removeElements(ListNode head, int val) {
        // 首先先判断极端情况
        if(head == null){
            return head;
        }
        // 如果不为空,就有可能头节点的值=val,所以要遍历到第一个不等于 val的节点
        while(head != null && head.val == val){
            head = head.next;
        }
        // 此时要么 head 为空了,要么 head.val!=val
        // 定义两个指针,一个用来遍历,一个用来定位当前节点的前一个节点。
        if(head == null){
            return head;
        }
        ListNode pre = head;
        ListNode cur = head.next;
        while(cur!=null){
            // 如果 cur.val == val,就要移除掉
            if(cur.val == val){
                pre.next = cur.next;
                cur = cur.next;
            }else{ // 如果不等于
                pre = cur;
                cur = cur.next;
            }
        }
        return head;    
    }
}

下面我们利用示例中的样例,通过图文表示,来描述下这个过程,让思路更加的清晰。
在这里插入图片描述

  • 此时的 head.val != val,就定义 pre = head , cur = head.next。
    在这里插入图片描述
  • 接下来就开始判断 cur 是否为空,cur.val 是否等于 val,此时 cur != null,并且 cur.val != val。 所以我们进行以下操作。cur = cur.next,pre = cur。 在这里插入图片描述
  • 继续根据上图,开始做判断,此时 cur != null,并且 cur.val = val。所以我们要进行以下操作,将 pre.next = cur.next。cur = cur.next。 在这里插入图片描述
  • 继续根据上图,开始做判断,此时 cur != null,并且 cur.val != val,所以我们进行以下操作,将 cur.next = next,pre = cur。 在这里插入图片描述
  • 继续根据上图,开始做判断,此时 cur != null,并且 cur.val != val,所以我们进行以下操作,将 cur.next = next,pre = cur。 在这里插入图片描述
  • 继续根据上图,开始做判断,此时 cur != null,并且 cur.val != val,所以我们进行以下操作,将 cur.next = next,pre = cur。 在这里插入图片描述
  • 继续根据上图,开始做判断,此时 cur != null,并且 cur.val = val。所以我们要进行以下操作,将 pre.next = cur.next。cur = cur.next。 在这里插入图片描述
  • 此时 cur = null, 退出循环。 返回 head。

LeetCode 707 设计链表

题目,让我设计一个链表,可以是单链表或者是双链表。此处我们就设计 一个带有虚拟头节点的单链表

  1. 获取链表第 index 个节点的值
  2. 在链表的最前面插入一个节点
  3. 在链表的末尾插入一个节点
  4. 在链表第index个节点前面插入一个节点
  5. 删除链表的第index个节点
public class MyLinkedList {
    static class ListNode {
        int val = 0;
        ListNode next;

        public ListNode(int val) {
            this.val = val;
        }
    }

    // 定义一个虚拟头节点
    ListNode head;
    int size = 0;
    // 实现一个单链表, 带虚拟头节点的
    public MyLinkedList() {
        // 记录元素个数
        head = new ListNode(0);
    }


    // 获取下标 index 节点的值
    public int get(int index) {
        ListNode currNode = head;
        if (index < 0 || index >= size) {
            return -1;
        }
        // index 满足条件
        for(int i=0; i<=index;i++){
            currNode = currNode.next;
        }
        return currNode.val;
    }


    // 头插
    public void addAtHead(int val) {
        addAtIndex(0,val);
    }

    // 尾插
    public void addAtTail(int val) {
        addAtIndex(size,val);
    }

    // 把值为 val的节点 追加到链表中下标为 index 的节点的前面
    public void addAtIndex(int index, int val) {
        if (index > size) {
            return;
        }
        ListNode node = new ListNode(val);
        ListNode currNode = head;
        // 如果 index 等于链表长度,直接加到末尾
        if (index < 0) {
            index = 0;
        }
        // 找到要插入的节点的 前驱节点
        while (index-- != 0) {
            currNode = currNode.next;
        }
        node.next = currNode.next;
        currNode.next = node;
        size++;
    }

    // 如果下标有效,删除下标为 index 的节点
    public void deleteAtIndex(int index) {
        // 如果下标小于0,或者>=size,下标不符合
        if (index < 0 || index >= size) {
            return;
        }
        ListNode currNode = head;
        // 找到要删除的下标 index 的前驱节点
        while (index-- != 0) {
            currNode = currNode.next;
        }
        currNode.next = currNode.next.next;
        size--;
    }
}

/**
 * Your MyLinkedList object will be instantiated and called as such:
 * MyLinkedList obj = new MyLinkedList();
 * int param_1 = obj.get(index);
 * obj.addAtHead(val);
 * obj.addAtTail(val);
 * obj.addAtIndex(index,val);
 * obj.deleteAtIndex(index);
 */

下图假设是链表的初始状态 在这里插入图片描述

下面一个一个分析这几个接口。

  • addAtIndex(2, 5) ,在下标为 2 的节点前,插入一个值为 5 的节点。
  1. 首选找到 下标为 2 的节点的前驱节点下标为1的节点,可以看到 curNode移动了两次,就是 index的值 2 在这里插入图片描述
  1. 找到前驱节点 curNode,将 node.next = curNode.next,curNode.next = node ,此时 size+1=5 在这里插入图片描述
  • deleteAtIndex(4) ,删除下标为 4 的节点。
  1. 首先还是找到下标为 4 的节点的前驱节点。可以看到 curNode 移动了4次,就是 index的值 4。 在这里插入图片描述 > 2. 然后让 curNode.next = curNode.next.next, size=size-1=4 在这里插入图片描述
  • get(2) ,获取下标为 2 的节点值
  1. 下标为2,根据下图分析,那么要遍历 3 次,才能定位到 下标 2 在这里插入图片描述
  1. 找到后,直接返回这个节点的值即可。
  • addAtHead(int val) ,在头插,就相当于在下标为 0 的地方插入,直接调用 addIndex(0,val) 即可
  • AddTail(int val) ,在尾插,就当于在尾巴插入,直接调用 addIndex(size,val) 即可

LeetCode 206 反转链表

本题思路:反转单链表。我们可以使用双指针来解决这个问题,定义个 pre=null,定义一个 cur = head 用来遍历这个链表。还需要定义一个 tmp 来保存记录 cur 的记录,因为遍历过程中,cur.next 会往前指,所以要保留 cur 原先的 next 地址。

class Solution {
    public ListNode reverseList(ListNode head) {
        if(head == null || head.next == null){
            return head;
        }
        ListNode pre = null;
        ListNode cur = head;
        // 定义一个临时指针
        ListNode tmp = null;
        while(cur != null){
            tmp = cur.next;
            cur.next = pre;
            pre = cur;
            cur = tmp;
        }
        return pre;
    }
}

下面用这个示例2,利用画图来一步一步分析步骤。
在这里插入图片描述

  • 首先初始状态如下在这里插入图片描述 在这里插入图片描述

  • 首先保存 tmp = cur.next,然后让 cur.next = pre,pre = cur 随后 cur = tmp 在这里插入图片描述

  • 首先保存 tmp = cur.next,然后让 cur.next = pre,pre = cur 随后 cur = tmp 在这里插入图片描述

  • 此时 cur == null,所以看图,返回 pre,就是新反转后的链表的头节点。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

代码随想录算法训练营Day3 | 203.移除链表元素、707.设计链表、59.螺旋矩阵II 的相关文章

  • Java反射机制详解

    1 什么是反射 Java反射机制是在运行时 动态地获取类 的信息并操作类或对象的能力 通过反射 可以在运行时检查类的属性 方法和构造函数 访问和修改对象的属性值 调用对象的方法 以及创建对象的实例等 其本质上是通过JVM编译得到的class
  • 中联重科2024届秋招/校招内推信息/内推码

    公司名称 中联重科 内推码 thgyfm 内推来源 内推鸭小程序 官方招聘网站 中联重科校招官网

随机推荐