代码随想录算法训练营第三天| 链表理论基础笔记,203.移除链表元素 ,707.设计链表,206.反转链表

链表基础理论笔记

链表是一种通过指针串联在一起的线性结构,每一个节点由两部分组成,一个是数据域一个指针域,最后一个节点的指针域指向null。链表的入口节点称为链表的头节点,head。

链表分为单链表、双链表以及循环链表,双链表每一个节点有两个指针域,一个指向下一个节点,一个指向上一个节点,既可向前查询也可向后查询。循环链表首尾相连,可以用来解决约瑟夫环问题。

链表在内存中不是连续分布的,散乱分布在内存中的某地址上,分配机制取决于操作系统的内存管理,通过指针域的指针链接在内存中的各个节点。

链表的定义

注意,如果不定义构造函数使用默认构造函数的话,在初始化的时候就不能直接给变量赋值!

链表的操作

删除某节点:只要将前一个节点的next指针指向该节点的后一个节点即可,在C++里最好再手动释放掉该节点,Java、Python有自己的内存回收机制,不用手动释放。

添加节点:先将需要插入位置的节点的指针赋给添加的节点的指针,再将前一个节点的指针指向新添加的节点即可。

与数组的区别

数组在定义的时候,长度就是固定的,如果想要改动数组的长度,就需要重新定义一个新的数组。数组的适用场景为:频繁查询,较少增删。

链表的长度可以是不固定的,并且可以动态增删,适用场景为:数据量不固定,频繁增删,较少查询。

Java版本的链表定义

public class ListNode {
    // 节点的值
    int val;
    // 下一个节点
    ListNode next;
    // 节点的构造函数(无参)
    public ListNode(){

    }
    // 节点的构造函数(有两个参数)
    public ListNode(int val, ListNode next){
        this.val = val;
        this.next = next;
    }
}

LeetCode 203.移除链表元素

题目要求删除链表中值等于val的节点,第一次用Java写链表删除,还不是很熟练,之前一直用C写题,while循环遍历时还在思考循环的条件要怎么来写,如果current是从dummyHead开始遍历的,由于要取值,所以不仅要判断current!=null还要current->next!=null,如果cureent是从head来遍历的则需要保存上一个节点,所以还需要一个变量来存储上一个节点,所以循环的条件就变为了current!=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 removeElements(ListNode head, int val) {
        ListNode dummyHead = new ListNode(-1, head);
        ListNode pre = dummyHead;
        ListNode current = head;
        while(current != null){
            if(current.val == val){
                pre.next = current.next;
            }else{
                pre = current;
            }
            current = current.next; // 更新current节点
        }
        return dummyHead.next; // 真正的head节点
    }
}

最后别忘了返回真正的head节点。

LeetCode 707设计链表

思路:代码写的磕磕绊绊,在挂了一次之后发现是增加节点和删除节点的循环条件不对,改了之后就过了。后来看了下讲解,发现自己的代码还有很大的优化空间,原始代码如下:

class LinkNode{
    int val;
    LinkNode next;
    public LinkNode(){}
    public LinkNode(int val){
        this.val = val;
    }
}

class MyLinkedList {
    int size; // 存储链表长度
    LinkNode head; // 虚拟头节点
    public MyLinkedList() {
        size = 0 ;
        head = new LinkNode(-1);
    }

    public int get(int index) {
        if(index < 0 || index >= size) return -1;
        LinkNode current = head;
        for(int i=0; i<=index; i++){
            current = current.next;
        }
        return current.val;
    }
    
    public void addAtHead(int val) {
        LinkNode newNode = new LinkNode(val);
        newNode.next = head.next;
        head.next = newNode;
        size++;
    }
    
    public void addAtTail(int val) {
        LinkNode current = head;
        while(current.next != null){ // 找到尾节点
            current = current.next;
        }
        LinkNode newNode = new LinkNode(val);
        current.next = newNode;
        size++;
    }
    
    public void addAtIndex(int index, int val) {
        if(index >= 0 && index <= size){
            if(index == 0){
                addAtHead(val);
            }else if(index == size){
                addAtTail(val);
            }else{
                LinkNode current = head;
                LinkNode newNode = new LinkNode(val);
                for(int i=0; i<index; i++){
                    current = current.next;
                }
                newNode.next = current.next;
                current.next = newNode;
                size++;
            }
        }
    }
    
    public void deleteAtIndex(int index) {
        if(index >= 0 && index < size){
            LinkNode current = head;
            for(int i=0; i<index; i++){
                current = current.next;
            }
            LinkNode delNode = current.next; // 暂存要删除的节点
            current.next = delNode.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);
 */

在看了文章之后,对代码进行优化如下:

class LinkNode{
    int val;
    LinkNode next;
    public LinkNode(){}
    public LinkNode(int val){
        this.val = val;
    }
}

class MyLinkedList {
    int size; // 存储链表长度
    LinkNode head; // 虚拟头节点
    public MyLinkedList() {
        size = 0 ;
        head = new LinkNode(-1);
    }

    public int get(int index) {
        if(index < 0 || index >= size) return -1;
        LinkNode current = head;
        for(int i=0; i<=index; i++){
            current = current.next;
        }
        return current.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 > size) return;
        if(index < 0) index = 0;
        LinkNode current = head;
        LinkNode newNode = new LinkNode(val);
        for(int i=0; i<index; i++){
            current = current.next;
        }
        newNode.next = current.next;
        current.next = newNode;
        size++;
    }
    
    public void deleteAtIndex(int index) {
        if(index >= 0 && index < size){
            LinkNode current = head;
            for(int i=0; i<index; i++){
                current = current.next;
            }
            LinkNode delNode = current.next; // 暂存要删除的节点
            current.next = delNode.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);
 */

加了虚拟头节点后,第i个节点变成了第i+1节点,增加节点和删除节点时,要注意循环次数。

LeetCode 206反转链表

刚开始没啥思路,在看了卡尔的视频讲解后明白了该怎么去做,双指针代码如下:

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

熟悉双指针解法后,尝试递归解法如下:

lass Solution {
    public ListNode reverse(ListNode current, ListNode pre){
        if(current == null) return pre;
        ListNode temp = current.next;
        current.next = pre;
        return reverse(temp, current);
    }
    public ListNode reverseList(ListNode head) {
        return reverse(head, null);
    }
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值