代码随想录LeetCode | 链表问题总结

前沿:撰写博客的目的是为了再刷时回顾和进一步完善,其次才是以教为学,所以如果有些博客写的较简陋,是为了保持进度不得已而为之,还请大家多多见谅。

预:看到题目后的思路和实现的代码。

见:参考答案展示。

感思:对比答案后的思考,与之前做过的题目是否有关联。

行:

(1)对于没做出来的题目,阅读答案后重新做一遍;

(2)下次做题可以尝试改善的方向;

(3)有助于理解的相关的题目

优先级:做题进度>学习&总结>默写回顾>做题数量

链表基础

为什么使用链表?

链表相对于数组的优势在于其便于插入和删除,而数组存储在连续的地址中,全部替换才能达到“删除”效果。

为什么链表便于插入和删除/时间复杂度n(1)?

与链表的存储和获取下一链表的方式有关。因为链表的存储是不连续的,而数组则是连续存储,链表其通过指针来获取下个节点的位置,所以只需要直接修改指针域则能够插入和删除指针。

链表的定义:链表结构中有指针域和val,val存储对于值,通过指针域来连接下个节点,单链表只有next,而双链表的指针域还有pre。

如何使用链表?

类似数组的创建形式:ListNode 名称 = new ListNode();

203. 移除链表元素

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

给你一个链表的头节点 head 和一个整数 val ,请你删除链表中所有满足 Node.val == val 的节点,并返回 新的头节点 。

代码随想录LeetCode | 链表问题总结_第1张图片

输入:head = [1,2,6,3,4,5,6], val = 6
输出:[1,2,3,4,5]

提示:

  • 列表中的节点数目在范围 [0, 104] 内
  • 1 <= Node.val <= 50
  • 0 <= val <= 50

实现代码

class Solution {
    public ListNode removeElements(ListNode head, int val) {
        ListNode dummyNode = new ListNode();
        dummyNode.next = head;
        ListNode pre = dummyNode;
        ListNode cur = dummyNode.next;
        while(cur != null){
            if(cur.val == val){
                pre.next = cur.next; // pre.next.next = pre.next;
            }else{ // 没有否定,直接后面增加pre = pre.next;
                pre = cur; 
            }
            cur = cur.next;
        }
        return dummyNode.next;
    }
}

与题解区别

        ListNode dummyNode = new ListNode();
        dummyNode.next = head;

上面的代码块能够通过直接调用构造函数实现

        ListNode dummyNode = new ListNode(-1,head);

707. 设计链表

思路图

代码随想录LeetCode | 链表问题总结_第2张图片

实现代码

链表的定义+链表实现相关操作类

class ListNode{
    int val;
    ListNode next;
    public ListNode(){

    }
    public ListNode(int val){
        this.val = val;
    }
}
class MyLinkedList {
    ListNode head = new ListNode();
    int len = 0;
    public MyLinkedList() {
    }
    
    public int get(int index) {
        if(index < 0 || index >= len){
            return -1;
        }
        ListNode cur = head.next;
        while(index != 0 && cur != null){
            cur = cur.next;
            index--;
        }
        return cur.val;        
    }
    
    public void addAtHead(int val) {
        addAtIndex(0,val);
    }
    
    public void addAtTail(int val) {
        addAtIndex(len,val);
    }
    
    public void addAtIndex(int index, int val) {
        if(index < 0){
            index = 0;
        }else if(index > len){
            return;
        }
        ListNode cur = head.next;
        ListNode pre = head;
        ListNode temp = new ListNode(val);
        while(index != 0 && cur != null){
            cur = cur.next;
            pre = pre.next;
            index--;
        }
        temp.next = cur;
        pre.next = temp;
        len++;
    }
    
    public void deleteAtIndex(int index) {
        if(index < 0 || index >= len){
            return;
        }
        ListNode cur = head;
        while(index != 0 && cur.next != null){
            cur = cur.next;
            index--;
        }
        cur.next = cur.next.next;
        len--;
    }
}

与题解的区别

1.定义中少了构造器初始多属性的方法

  • 无参构造器为属性设置默认初始值
class ListNode{
        public ListNode(int val,ListNode next}{
            this.val = val;
            this.next = next;
        }
}
class MyLinkedList {
    int len;
    ListNode head;
    public MyLinkedList() {
        head = new ListNode(0); 
        len = 0;
    }

2. 能够直接通过改动变量+前节点变量直接添加新变量

     public void addAtIndex(int index, int val) {
        ListNode pre = head;
        for(int i = 0;i < index;i++){
            pre = pre.next;
        }
        ListNode toAdd = new ListNode(val);
        toAdd.next = pre.next;  //可能会空指针报错
        pre.next = toAdd;
        len++;
    }

206. 反转链表

思路图

代码随想录LeetCode | 链表问题总结_第3张图片

  题解代码

class Solution {
    public ListNode reverseList(ListNode head) {
        // ListNode dummyNode = new ListNode(-1,head);
        ListNode pre = null;
        ListNode cur = head;
        ListNode temp = null;
        while(cur != null){
            temp = cur.next;
            cur.next = pre;
            pre = cur;
            cur = temp;
        }
        return pre;
    }
}

为什么二刷时仍然画不出来呢?

二刷:思考10分钟,感觉总是画不出循环遍历的闭环。

看完题解总结后,重新思考一下子就顺着题解写出来,但对于当时为什么画不出来就想不到了。

所以,当思考后做不出来时,要将画的思路图拍照或写下来的形式记录下来,因为问题是顽固的。

为什么三刷时画出来了还做不出来?

三刷:

看到这题就想到要画出来再实现,前面10分钟画出来的有问题,之后找到的正确画法(如下图),但仍实现有问题,就在纠结是否是顺序问题。

代码随想录LeetCode | 链表问题总结_第4张图片

 有问题代码如下

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

代码实现与画图不一致

实现代码中是dummyNode指向head,并不是如图上面的head指向dummyNode;

  • cur.next = pre→导致dummyNode和cur成环了;

代码随想录LeetCode | 链表问题总结_第5张图片

刷题模式优化:记录做不出来时想的思路

刷题记录

代码随想录LeetCode | 链表问题总结_第6张图片

代码随想录LeetCode | 链表问题总结_第7张图片

代码随想录LeetCode | 链表问题总结_第8张图片

你可能感兴趣的:(链表,数据结构,java,leetcode)