随想录训练营Day3 | 链表基础, 707. 设计链表, 206. 反转链表,203. 移除链表元素
标签: LeetCode闯关记
我的扫盲贴: 链表的理论基础 三种:单链表,双链表,循环链表; 链表定义:
public class ListNode {
//结点的值
int val;
//下一个结点
ListNode next;
//节点的无参构造器
public ListNode() {
}
//节点的构造器(一个参数)
public ListNode(int val) {
this.val = val;
}
//节点的构造器(两个参数)
public ListNode(int val, ListNode next) {
this.val = val;
this.next = next;
}
}
删除单链表元素: especially, 考虑头结点的特殊性,所以添加虚拟节点.
//添加虚拟节点以统一删除方式
public class ListNode {
//结点的值
int val;
//下一个结点
ListNode next;
//节点的无参构造器
public ListNode() {
}
//节点的构造器(一个参数)
public ListNode(int val) {
this.val = val;
}
//节点的构造器(两个参数)
public ListNode(int val, ListNode next) {
this.val = val;
this.next = next;
}
public ListNode removeElement(ListNode head, int val){
if(head == null){
return head;
}
ListNode dummy = new ListNode(-1,head);
ListNode pre = dummy;
ListNode cur = head;
while(cur != null){
if(cur.val == val){
pre.next = cur.next;
pre = cur;
}else{
pre = cur;
}
cur = cur.next;
}
return dummy.next;
}
**1. 707. 设计链表 ** 1.1 题目 相关链接: 707. 设计链表
坑点:假设链表中的所有节点下标从 0 开始。 因为一般,设置dummy节点的操作,ListNode dummy = new ListNode(-1, head);
###1.2 解题思路 链表的基础操作:增删查;
- 增: 先寻找第n-1个结点,再插入,重点:注意插入顺序;
- 删: 先寻找第n-1个结点,再;是删除,直接将指针指向后一个结点;
- 查: ①在头结点之前;②在尾结点;③在链表的任何位置; 通过构造虚拟头结点,使所有情况统一运用一种方法:即寻找第n-1个结点,以此访问第n个结点;
###1.3 遇到问题 问题很多,特别是for循环的循环条件的边界值,很痛苦 问题代码如下:
//单链表
class ListNode{
int val;
ListNode next;
ListNode(){};
ListNode(int val){
this.val =val;
}
}
class MyLinkedList {
int size;
ListNode dummyHead;
//初始化链表
public MyLinkedList(){
size = 0;
dummyHead = new ListNode(0);//我看卡哥解题思路的话,这里的index=0时,是找的虚拟头结点;
}
public int get(int index) {//链表有下标? 没得,但是可以用for循环得到第index个
//合法性检验
if(index < 0 || index >= size){
return -1;
}
ListNode cur = dummyHead;
//搞清楚所有节点下标从"0"开始,有虚拟头结点,如何找到第n个结点,很重要!
//取值问题,考虑极端情况,如,index = 0时,其实是找除虚拟头结点外第一个结点;
//以下的取值范围满足极端情况,则通过检验;
for(int i = 0; i<= index; i++){
cur =cur.next;
}
return cur.val;
}
//在链表的头结点前(注意,不是虚拟头结点)插入一个节点
public void addAtHead(int val) {
ListNode p = new ListNode(val);
//插入顺序很重要,详见讲解视频
p.next = dummyHead.next;
dummyHead.next = p;
size++;
}
//在链表的最后插入一个节点
public void addAtTail(int val) {
ListNode cur = dummyHead;
ListNode q = new ListNode(val);
for(int j = 0; j <= size - 1; j++){ //???
cur = cur.next;
}//使cur指向链表的最后一个元素
cur.next = q;
size++;
}
//区分:(???????????)
//index:从真实头结点开始算,以0开始;(不算虚拟头结点);
//size:从真实头结点开始算,以1开始;
//所以,index = size -1;
//但是在真实头结点之前,还有一个虚拟头结点;
public void addAtIndex(int index, int val) {
if(index < 0 || index > size - 1){//不懂这里index > ? → 懂了
return;
}
ListNode p = new ListNode(val);
ListNode cur = dummyHead;
//找到第index-1的元素
for(int i = 0; i <= index - 1; i++){
cur = cur.next;
}
//顺序很重要,详见讲解视频
p.next = cur.next;
cur.next = p;
size++;
}
public void deleteAtIndex(int index) {
ListNode cur = dummyHead;
//找到第index-1的元素
for(int i = 0; i <= index - 1; i++){
cur = cur.next;
}
cur.next =cur.next.next;
size--;
}
}
报错: 结果错误(没找到原因) (暂时贴不出来图,待更新) ###1.4 算法实现 算法分析 待修改后上传;
注意点: 虚拟头结点引入的原因: 单链表的特殊性_____只能指向下一个节点,需要考虑删除的是头结点这种特殊情况.
###1.5 题目总结 解题耗时:1.5h + 无穷无尽的看边界条件 ###1.6 相关题目
##2. 206. 反转链表 ###2.1 题目 题目:206. 反转链表 讲解视频: www.bilibili.com/video/BV1nB… ###2.2 解题思路 ###2.3 遇到问题 无 ###2.4 实现代码 法1; 双指针法
class Solution {
public ListNode reverseList(ListNode head) {
//初始化:注意为什么pre得是null;
ListNode pre = null;
ListNode cur = head;
ListNode temp = null;
//双指针
while(cur != null){//注意终止条件
temp = cur.next; //交换的顺序很重要,忘记的话看讲解视频
cur.next = pre;
pre = cur;
cur = temp;
}
return pre;
}
}
注意点:
法2:根据双指针法抽象得到的递归法
//对照双指针方法写下的递归,感觉跟我遇到的普通递归很不一样,这里的递归边界条件是cur == null;递归体是指针指向位置的变化,递归函数的代入值的改变完成了双指针方法中两个指针的前进.
class Solution {
public ListNode reverseList(ListNode head) {
return reverse(null, head);
}
private ListNode reverse(ListNode pre, ListNode cur){
ListNode temp = null;
if(cur == null){return pre;}//递归边界条件
temp = cur.next;// 先保存下一个节点
cur.next = prev;// 反转
// 更新prev、cur位置
// prev = cur;
// cur = temp;
return reverse(cur, temp);//递归函数的代入值的改变完成了双指针方法中两个指针的前进
}
}
###2.5 题目总结 双指针!
###2.6 相关题目
##**3.203. 移除链表元素 ** ###3.1 题目 相关链接 203. 移除链表元素
###3.2 解题思路 永远记住,链表相关问题,永远是找到index - 1 的元素,以此操作index元素 用pre指针来找index-1 元素; ###3.3 遇到问题 无 ###3.4 算法实现
class Solution {
public ListNode removeElements(ListNode head, int val) {
ListNode dummy = new ListNode(-1, head);
ListNode pre = dummy;
ListNode cur = head;
while(cur != null){
if(cur.val == val){
pre.next = cur.next;//永远记住,链表相关问题,永远是找到index - 1 的元素,以此操作index元素
}else{
pre = cur;
}
cur = cur.next;
}
return dummy.next;
}
}
注意点:待更新
###3.5 题目总结
###3.6 相关题目
##4. 今日心得 设计链表令人疲惫..... 这格式.......emmmmm找个时间全部更新一下,太恶心额.