当前位置: 首页 > news >正文

代码随想录算法训练营第3天(链表1)| 203.移除链表元素 707.设计链表 206.反转链表

一、203.移除链表元素

题目:203. 移除链表元素 - 力扣(LeetCode)

视频:手把手带你学会操作链表 | LeetCode:203.移除链表元素_哔哩哔哩_bilibili

讲解:代码随想录

注意:

针对头结点和非头结点的删除方式是不一样的:

正常节点:要找到该节点的上一节点

头结点:直接把 head 往后移一位

所以就要进行判断,要删除的节点是不是头结点(方法一)

或者,在头结点前设立一个虚拟节点(dummy head)(方法二)

方法一:判断链表删除元素

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

要点 1:

判断头结点是否符合的时候,使用 if 就只能判断一次,如果第二个元素也符合条件,就漏删了

所以要用 while ,在头结点不符合条件的时候,才继续往下走

要点 2:

往后查找的时候,要定义一个指针,那么指针的位置指向哪里?

如果是第二位,第二位符合删除条件,找不到上一位的 next 指针。(x)

所以要指向头结点

尝试过程:

class Solution {public ListNode removeElements(ListNode head, int val) {while (head != null && head.val == val) {head = head.next;}ListNode curr = head;while (curr.next != null && curr != null) {     //这里有问题!!if (curr.next.val == val) {curr.next = curr.next.next;} else {curr = curr.next;}}return head;}
}

报这个错误的原因:

虽然从逻辑上看是想同时确保当前节点 curr 和它的下一个节点 curr.next 都不为 null,但如果 curr 本身已经是 null 了,再去访问 curr.next 就会直接抛出空指针异常。

正确的做法应该是先判断 curr 是否为 null再去判断 curr.next 是否为 null,像这样修改条件为 while (curr!= null && curr.next!= null)

方法二:设置虚拟头结点

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

注意头结点的指针是不能更改的,因为最后要用到头结点返回。

二、707.设计链表

题目:707. 设计链表 - 力扣(LeetCode)

视频:帮你把链表操作学个通透!LeetCode:707.设计链表_哔哩哔哩_bilibili

讲解:代码随想录

利用虚拟头结点方式,对所有结点统一操作

curr 指针从什么位置开始

循环从什么地方结束

增加/删除时几个指针的操作顺序

class ListNode {    //定义链表ListNode next;int val;public ListNode() {}public ListNode(int val){this.val = val;}
}class MyLinkedList {ListNode dummy;int size;//以此开始public MyLinkedList() {    //初始化size = 0;dummy = new ListNode(-1);}public int get(int index) {    //获取if(index < 0 || index > size-1) return -1;ListNode cur = dummy;for(int i=0; i < index; i++){cur = cur.next;}return cur.next.val;}public void addAtHead(int val) {   //addAtIndex(0, val);        }public void addAtTail(int val) {     //addAtIndex(size, val);}public void addAtIndex(int index, int val) {   //插入if(index < 0 || index > size)  return;ListNode newNode = new ListNode(val);ListNode curr = dummy;for(int i = 0; i < index; i++){curr = curr.next;}newNode.next = curr.next;curr.next = newNode;size++;      }public void deleteAtIndex(int index) {   //删除if(index < 0 || index > size-1) return;ListNode curr = dummy;for(int i = 0; i < index; i++){curr = curr.next;}curr.next = curr.next.next;size--;}
}
class MyLinkedList {class ListNode {int val;ListNode next;ListNode(int val) {this.val = val;}}private int size;private ListNode head;// 初始化public MyLinkedList() {this.size = 0;this.head = new ListNode(0);}public int get(int index) {if (index < 0 || index >= size) {return -1;}ListNode cur = head;for (int i = 0; i <= index; i++) {cur = cur.next;}return cur.val;}public void addAtHead(int val) {ListNode newNode = new ListNode(val);newNode.next = head.next;head.next = newNode;size++;}public void addAtTail(int val) {ListNode newNode = new ListNode(val);ListNode cur = head;while (cur.next != null) {cur = cur.next;}cur.next = newNode;size++;}public void addAtIndex(int index, int val) {if (index < 0 || index >= size) {return;}ListNode cur = head;for (int i = 0; i < index; i++) {cur = cur.next;}ListNode newNode = new ListNode(val);newNode.next = cur.next;cur.next = newNode;size++;}public void deleteAtIndex(int index) {if(index < 0 || index >=size){return;}ListNode cur = head;for(int i=0; i<index; i++){cur = cur.next;}cur.next = cur.next.next;size--;}
}

要点是要确定每个循环停在哪里,否则会报空指针异常

三、206.反转链表

题目:206. 反转链表 - 力扣(LeetCode)

视频:帮你拿下反转链表 | LeetCode:206.反转链表 | 双指针法 | 递归法_哔哩哔哩_bilibili

讲解:代码随想录

要点:

1、 两个指针(加上 temp 是三个指针)的起始位置

2、 循环的终止条件

3、 调换每一个节点,调整的顺序

正确答案:

class Solution {public ListNode reverseList(ListNode head) {if(head == null || head.next == null) return head;ListNode pre = null;ListNode cur = head;ListNode temp;while(cur != null){temp = cur.next;cur.next = pre;pre = cur;cur = temp;}return pre;}
}

尝试过程:

class Solution {public ListNode reverseList(ListNode head) {if(head == null || head.next == null) return head;ListNode pre = null;ListNode cur = head;ListNode temp;for(int i = 0; i <= head.size-1; i++){   //这里报错!!temp = cur.next;cur.next = pre;pre = cur;cur = temp;}return pre;}
}

错误原因:ListNode类并没有定义size属性。在链表中,我们通常通过遍历来获取链表的长度,而不是直接存储长度。

四、链表总结

1、虚拟头结点:如果想要针对不同位置(头与非头结点)的节点用相同的处理办法,可以考虑虚拟头结点,对所有节点一视同仁。

2、双指针:节省空间

3、注意几个调整动作的先后顺序,防止指针丢失的结果。


http://www.mrgr.cn/news/83457.html

相关文章:

  • Windows上使用VSCode开发linux C++程序
  • 【面试题】简单聊一下什么是云原生、什么是k8s、容器,容器与虚机相比优势
  • [SMARTFORMS] 翻页打印
  • Spring Cloud 集成AlloyDB
  • java通过ocr实现识别pdf中的文字
  • HarmonyOS 鸿蒙Next 预览pdf文件
  • 卷积神经02-CUDA+Pytorch环境安装
  • 初识 Git——《Pro Git》
  • 哈希表及模拟实现
  • 【老白学 Java】项目演练 - Quizzes #3
  • nvim 打造成可用的IDE(2)
  • 性能测试04|JMeter:连接数据库、逻辑控制器、定时器
  • 二分答案(进阶)
  • HarmonyOS:@LocalBuilder装饰器: 维持组件父子关系
  • 算法题(32):三数之和
  • C语言数据结构与算法(排序)详细版
  • 如何让QPS提升20倍
  • AI人工智能(2):机器学习
  • SCI科研论文配色方案:色彩丰富的情况下就是白背景;浅色系
  • OCR文字识别—基于PP-OCR模型实现ONNX C++推理部署
  • 赛灵思(Xilinx)公司Artix-7系列FPGA
  • 【Linux】正则表达式
  • Vue2+OpenLayers调用WMTS服务初始化天地图示例
  • git lfs
  • Docker 基础知识
  • Flyte工作流平台调研(四)——服务部署