首页 > 其他分享 >day 3 链表 203.移除链表元素、707.设计链表、206.反转链表

day 3 链表 203.移除链表元素、707.设计链表、206.反转链表

时间:2023-10-27 19:01:15浏览次数:35  
标签:203 ListNode cur val next 链表 移除 节点

203.移除链表元素

题目链接:203.移除链表元素

视频教程

文字教程

虚拟头节点

虚拟头节点的目的:消除头节点的特殊性

  • 痛点:删除头节点和删除其他节点的操作是不一样的,导致写代码时需要分两种情况考虑
    • 因为其他链表都是通过前一个节点删除的
    • 而头节点没有前一个节点,只需将头节点向后移动一位即可删除

因此为了进一步优化,可以用一种统一的逻辑来删除所有节点,就必须使所有节点 (特指头节点) 都拥有前一个节点

所有节点都拥有前一个节点可以保证头节点和其他节点删除的逻辑保持一致 (这里有点啰嗦,但这点很重要,理解了这点就能理解为什么虚拟头节点这么好使了)

来用这张图看一看如何使用虚拟头节点。

这里来给链表添加一个虚拟头节点成为新的头节点,此时要移除这个旧的头节点 1 。

这里是不是就可以将删除头节点和删除其他节点的方式统一了

代码实现

/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode() {}
 *     ListNode(int val) { this.val = val; }
 *     ListNode(int val, ListNode next) { this.val = val; this.next = next; }
 * }
 */
class Solution {
    public ListNode removeElements(ListNode head, int val) {
        ListNode dummyHead = new ListNode(); // 设置虚拟头节点
        dummyHead.next = head; // 虚拟头节点的next指向head
        ListNode cur = dummyHead; // 利用cur遍历链表
        while (cur.next != null) {
            if (cur.next.val == val) {
                cur.next = cur.next.next; // 删除 val==target 的节点,并cur.next指向下一个节点 
            } else {
                cur = cur.next; // cur指向下一个节点
            }
        }
        return dummyHead.next; // 这里返回真正的头节点
    }
}

707.设计链表

题目链接:707.设计链表

视频教程

文字教程

思路

  • 这道题涉及了五个接口的实现:

    • 获取链表第Index个节点的数值

    • 在链表的最前面插入一个节点

    • 在链表的最后面插入一个节点

    • 在链表第index个节点前面插入一个节点

    • 删除链表的第index个节点

  • 核心思路在链表中寻找特定位置的节点 cur

    核心代码:(本人只提供其中一种方式)

    cur = head; // cur 指向头节点
    for(int i = 0;i < index;i++) {
        cur = cur.next;
    }
    

    for(int i = 0;i < index;i++) 说明:

    • 这段代码中的 < 可以换为 <= ,根据条件而定
    • 这段代码中的 index 可以换位 size ,根据条件而定

代码实现

纠正一点我之前的错误,Java不允许用 int 作为 boolean 使用

错误代码,仅供批斗:

while (index--) {   // 报错信息:int cannot be converted to boolean
    cur = cur.next;
}

正确代码:

注意中间多次设计链表的循环,循环条件和 cur 的赋值是什么容易错误的点

class ListNode {

    int val;

    ListNode next;

    public ListNode() {

    };

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

class MyLinkedList {

    ListNode head;

    int size;

    public MyLinkedList() {
        head = new ListNode(0);
        size = 0;
    }
    
    public int get(int index) {
        if (index < 0 || index >= size) {
            return -1;
        }
        ListNode cur = head; 
        for (int i = 0;i <= index;i++) { // 这个利用index循环找位置的技巧很常用, 循环条件要注意
            cur = cur.next;
        }
        return cur.val;
    }
    
    public void addAtHead(int val) {
        ListNode node = new ListNode(val);
        node.next = head.next;
        head.next = node;
        size++;
    }
    
    public void addAtTail(int val) {
        ListNode node = new ListNode(val);
        ListNode cur = head;
        for (int i = 0;i < size;i++) { 
            cur = cur.next;
        }
        cur.next = node;
        size++;
    }
    
    public void addAtIndex(int index, int val) {
        if (index > size) {
            return;
        } else if (index == size) {
            addAtTail(val);
        } else if (index < 0) {
            addAtHead(val);
        } else {
            ListNode node = new ListNode(val);
            ListNode cur = head;
            for (int i = 0;i < index;i++) { 
                cur = cur.next; // 找到添加位置的前一个节点
            }
            node.next = cur.next;
            cur.next = node;
            size++;
        }
    }
    
    public void deleteAtIndex(int index) {
        if (index >= 0 && index < size) {
            ListNode cur = head;
            for (int i = 0;i < index;i++) {
                cur = cur.next; // 找到删除位置的前一个节点
            }
            cur.next = cur.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);
 */

206.反转链表

题目链接: 206.反转链表

视频教程

文字教程

思路

本题只需要改变链表的next指针的指向,直接将链表反转,实现时间复杂度:O(n) 空间复杂度:O(1),如图所示:

  • 双指针的实现思路:利用前后指针在遍历链表的同时改变指针next

    利用双指针实现反转链表的过程:(纠正:动画应该是先移动pre,在移动cur

  • 实现过程:

    • 首先定义两个指针,一个是 cur 指向head,一个是 pre 初始化为 null

    • 再定义一个临时存储节点,每次循环要先把 cur.next 节点用tmp保存起来(原因可以看代码实现里的注释)

    • 循环条件要设定为 cur==null因为只有 cur 通过循环条件才能转向 next

    • 循环体:

      tmp = cur.next;
      cur.next = pre;
      pre = cur;
      cur = tmp;
      
    • return 时要返回 pre ,此时 pre 指向反转后的头节点,cur 指向 null

代码实现

/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode() {}
 *     ListNode(int val) { this.val = val; }
 *     ListNode(int val, ListNode next) { this.val = val; this.next = next; }
 * }
 */
class Solution {
    public ListNode reverseList(ListNode head) {
        ListNode cur = head; // 遍历链表的当前节点
        ListNode pre = null; // 遍历链表的前一个节点
        ListNode tmp; // 临时存储cur节点的下一个节点
        while (cur != null) { // 循环条件中可以通过哪些节点,哪些节点的next才会被反转
            tmp = cur.next; // 临时节点先存储cur的下一个节点,因为下面cur.next要指向pre
            cur.next = pre; // cur.next指向pre
            pre = cur; // pre指向下一个节点
            cur = tmp; // cur指向下一个节点 
        }
        return pre;
    }
}

标签:203,ListNode,cur,val,next,链表,移除,节点
From: https://www.cnblogs.com/bobochicken/p/17792995.html

相关文章

  • 代码随想录第三天 | 203.移除链表元素 707.设计链表 206.反转链表
    第一题:https://leetcode.cn/problems/remove-linked-list-elements/我一开始打算是搞先判断第一个节点是不是,如果不是就作为头节点来着,不过后来一想觉得太麻烦了,仔细一看题目发现居然已经提供了模拟头节点的方法,就用了呗GPT3.5:那你我的想法有颇多相似之处啊.jpg第二题:https://l......
  • 双向链表的建立和使用场景
    双向链表(DoublyLinkedList)是一种常见的数据结构,它在链表的基础上增加了一个指向前一个节点的指针,这使得在双向链表中可以方便地进行双向遍历。创建双向链表的步骤:定义节点类:首先,定义一个节点类,这个节点类通常包含三个属性:数据域(存储数据的部分)、指向下一个节点的指针(通常称为n......
  • 04_两两交换链表中的节点
    两两交换链表中的节点给定一个链表,两两交换其中相邻的节点,并返回交换后的链表。你不能只是单纯的改变节点内部的值,而是需要实际的进行节点交换。【思路】/***Definitionforsingly-linkedlist.*publicclassListNode{*intval;*ListNodenext;*......
  • 代码随想录算法训练营第一天 | 704. 二分查找,27. 移除元素
    今日学习的文章链接和视频链接https://programmercarl.com/数组理论基础.html二分查找二分查找最开始看到感觉比较简单,随手写出来了左闭右闭的情况,从来没想过左闭右开的情况,涨了见识varsearch=function(nums,target){letlow=0;letheigh=nums.length;......
  • 面试必刷TOP101:13、判断一个链表是否为回文结构
    一、题目二、题解2.1方法一使用list列表因为需要判断是否为回文结构,所以要比较头尾的数据,而链表无法随机查询数据,所以可以先将链表转换成list。具体步骤首先初始化一个list列表;遍历链表,将链表中的值转移至list中;在list中通过比较头尾的值来判断链表是否为回文结构。代码如下:import......
  • 03_反转链表
    反转链表给你单链表的头节点head,请你反转链表,并返回反转后的链表。力扣题目链接示例1:输入:head=[1,2,3,4,5]输出:[5,4,3,2,1]示例2:输入:head=[1,2]输出:[2,1]示例3:输入:head=[]输出:[]提示:链表中节点的数目范围是[0,5000]-5000<=Node.val<=5000思......
  • 代码随想录第一天 | 704. 二分查找 、 27. 移除元素
    https://leetcode.cn/problems/binary-search/第一眼看到题目的时候下意识直接搞了暴力搜索(一个一个对比),后来觉得时间复杂度太高了,就搞了二分法,之后再看文章,思路透彻了很多,因为我之前写二分法都是凭感觉,没有仔细琢磨过 https://leetcode.cn/problems/remove-element/帅!otto ......
  • 单向链表学习总结
        直接上代码了,看着在代码上面建立的链表类,大概可以说出啥是链表,这个是单向链表的一个类,链表有它的链表头,还有结点,建立一个结点类,结点有它的值和指向,指向的代码实现直接赋值Node类,然后链表头也和结点有些关系,因此把头设为结点类,然后弄一个构造函数,方便链表初始化  ......
  • 27.移除元素
    1.题目介绍给你一个数组nums和一个值val,你需要原地移除所有数值等于val的元素,并返回移除后数组的新长度。不要使用额外的数组空间,你必须仅使用O(1)额外空间并原地修改输入数组。元素的顺序可以改变。你不需要考虑数组中超出新长度后面的元素。说明:为什么返回数......
  • K 个一组翻转链表
    /***Definitionforsingly-linkedlist.*publicclassListNode{*intval;*ListNodenext;*ListNode(){}*ListNode(intval){this.val=val;}*ListNode(intval,ListNodenext){this.val=val;this.next=next;}*}......