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

前言:

说些废话。下周一有个面试,明天应该没办法刷题了,打算skip一天,面试之后补上。今天的题都是以前刷过的,快速的过一遍,后面再查漏补缺。以前自己刷题的时候,时常因为一些突然的安排而打乱节奏,希望这次在训练营能够坚持下去,加油啊!

链表理论基础

linked list相关的操作主要通过修改指针指向的node来实现

删除node时,c++需要手动释放内存

比较linked list 和 array:

        linked list, 查询较少, 增删频繁

        array: 查询频繁, 增删较少

        array 长度固定,linked list可以动态增减

203.移除链表元素

思路: 遍历链表时,如果下一个节点的值等于val,让节点next指针直接指向下下一个节点

实现:当删除某一个节点时,我们需要通过前一个节点进行操作,但链表的head 之前没有节点,我们是通过 head = head.next 来实现。 因此我们可以单独写一段code来处理删除head的情况,更好的方式是通过设置一个虚拟头节点,指向head,这样linked list上所有的节点都可以按照统一的方式进行删除。

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

707.设计链表

思路: 通过之前203的练习可以发现,在删除某一节点时,通过增加dummy head可以统一head 和非head节点的操作。 在某一位置插入节点同理,可以通过dummy head来操作。

实现: 初始化时定义一个dummy head , 用size记录链表的长度

注意: 当addAtIndex() 中判断index是否有效时, 不同于get() 和 deleteAtIndex(), 需要判断 index > size 而不是index >= size, 因为当需要增加节点时,index = size 的位置相当于在链表的尾部增加一个节点,是有效的。

class MyLinkedList {
    class listNode {
        int val;
        listNode next;
        listNode(int val){
            this.val = val;
        }
    }
    //定义dummy head 和size
    private listNode head;
    private int size;

    public MyLinkedList() {
        this.head = new listNode(0);
        this.size = 0; // size 并不包含 dummy head
    }
    
    public int get(int index) {
        // 通过size 判断index是否超过范围
        if( index < 0 || index >= size){
            return -1;
        }

        // index 0 是head, 所以寻找 index + 1 的节点
        listNode cur = head;
        for( int i = 0; i < index + 1; 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){ 
           //为什么不是index >= size, 因为index 为size时是有效的,相当于add at the tail
            return;
        }
        // 在index + 1的位置插入新节点
        listNode newNode = new listNode(val);
        listNode pre = head;
        // 到达index, 也就是插入节点的前一节点
        for(int i = 0; i < index; i++){
            pre = pre.next;
        }
        newNode.next = pre.next;
        pre.next = newNode;
        size++;
    }
    
    public void deleteAtIndex(int index) {
        if (index < 0 || index >= size) {
            return;
        }
        listNode pre = head;
        for(int i = 0; i < index; i++){
            pre = pre.next;
        }
        pre.next = pre.next.next;
        size--;
    }
}

206.反转链表  

思路: 链表的操作其实就是指针的操作,反转链表只需要改变next 指针的方向。

实现: 指针cur 遍历整个链表, 在这个过程中, 需要一个temp指针,先保存cur.next.  以及一个pre指针,指向cur的前一个节点,将 cur.next 指向 pre 实现翻转 

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

总结

涉及修改链表,如插入、删除、和移动,使用dummy head, 统一头节点和其他节点的处理 ...

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值