代码随想录算法训练营day03——链表章节(1)203.移除链表元素,707.设计链表,206.反转链表

参考教程:

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

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

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

完成情况:自我可实现

203.移除链表元素

思路:简单的链表结果的删除操作的练习。但是其中可以引起重视的思想有:

  1. 若不增加首节点,而是直接操作头节点的删除——头节点的删除是与其他节点删除的情况不一样,需要单独的写一段逻辑来进行处理。这样的好处在于删除后续节点时逻辑清晰,且再也不用考虑头节点会是待删除的元素。
  2. 增加首节点后(也即虚拟节点)那么所有节点的删除操作是一样的。但是需要注意的是需要再定义一个指针(引用)来遍历含有首节点的链表☆。

代码实现:

// 时间复杂度O(n),空间复杂度O(1),定义了虚拟的头结点
class Solution {
    public ListNode removeElements(ListNode head, int val) {
        
        //创建一个首节点
        
        ListNode fast=new ListNode(val-1);
        fast.next=head;
        ListNode res=fast;
        
        // 关于这道题,我原来的解法是让fast指针在往后走动遍历,这里是错误的
        // 原因在于fast是首节点,保存的就是整个链表的全部信息,如果fast指针next位置产生变化,则最后是找不到链表的可行head在哪里;其实移动也可以,只要head不为null,head.next不为null,fast完全可以自己移动
        while(res.next!=null){
            if(res.next.val==val){
                res.next=res.next.next;
            }else{
                res=res.next;
            }
        }
        return fast.next;
    }
}

 707.设计链表

思路:设计题,修修补补停不下来 ┭┮﹏┭┮

        需要记忆的点有:① 链表可插入节点的范围是[0,length];② 链表可删除节点的范围是[0,length-1];

代码实现:

class MyLinkedList {

    public Node head;
    public int length;

    // 建立链表,那么无需做任何其他的事情
    public MyLinkedList() {
        this.head = null;
        this.length = 0;
    }
    
    public int get(int index) {
        if(index>=0 && index<this.length){
            int count = 0;
            Node p = this.head;
            while(p != null){
                if(count == index)
                    return p.val;
                p=p.next;
                count++;
            }
        }
        return -1;
    }
    
    public void addAtHead(int val) {
        Node node = new Node(); //创建一个新的节点
        node.val = val;
        node.next = this.head;
        this.head = node;
        this.length++;
    }
    
    public void addAtTail(int val) {

        // 当前链表内没有节点
        if(this.length == 0){
            addAtHead(val);
            return;
        }

        Node p = this.head;
        while(p != null && p.next != null){
            p = p.next;
        }
        // p所停止的位置是最后一个节点
        Node node = new Node();
        node.val = val;
        node.next = null;
        p.next = node;     // 尾部插入
        this.length++;
    }
    
    public void addAtIndex(int index, int val) {
        
        if(index>=0 && index<=this.length){

            if(this.length == 0 || this.head==null){
                addAtHead(val);
                return;
            }
            // 先构建待添加的节点
            Node node = new Node();
            node.val = val;
            node.next = null;

            // 开始插入
            int count = 0;
            Node p = this.head;     // 指向头结点,准备开始遍历
            Node q = this.head;
            while(p!=null){
                if(count == index){
                    if(count == 0){
                        node.next = this.head;
                        this.head = node;
                        this.length++;
                        return;
                    }
                    else{
                        node.next = q.next;
                        q.next = node; 
                        this.length++;
                        return;
                    }
                    
                } // end if
                q = p;
                p = p.next;
                count++;

                // 在末尾添加节点
                if(index == this.length && count == this.length){
                    q.next = node;
                    this.length++;
                    return;
                }
            } // end while
            
        }
        
        return;
    }
    
    public void deleteAtIndex(int index) {

        if(index>=0 && index<this.length){
            Node q = this.head;
            int count = 0;
            while(count < this.length){
                if(count == index){
                    if(index == 0){
                        this.head = this.head.next;
                        this.length--;;
                        return;
                    }
                    else{
                        q.next = q.next.next;
                        this.length--;
                        return;
                    }
                }
                if(count == 0)
                    count++;
                else{
                    count++;
                    q = q.next;
                }
            } // end while
        } // end if

        return;
    }
}

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

/**
 * 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);
 */

206.反转链表

思路:设计一个新的虚拟节点,然后通过链表的指针的优势,遍历原链表时将每一个可行的节点采用“头插法”插入新的链表,从而实现翻转;

代码实现:

/**
 * 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; }
 * }
 */

// 时间复杂度O(n),空间复杂度O(1),建立了虚拟首节点
class Solution {
    public ListNode reverseList(ListNode head) {

        ListNode tail = head;   // 标记翻转之后的列表的尾结点是原来链表的头节点
        ListNode res = new ListNode();
        res.next = null;
        ListNode p = head;

        // 两个条件的判断可以有效防止head是null
        while(p!=null){
            // 当前的p是一个可行的节点
            ListNode q = p.next;    // 保存原来链表的下一个节点的地址
            p.next = res.next;      // 实现逆转
            res.next = p;           // 将新的可行节点放到开头去
            p = q;                  // 继续遍历原来的链表
        }
        // p已经移动到最后一个节点

        return res.next;
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值