代码随想录算法训练营第3天 | 203.移除链表元素、707.设计链表、206.反转链表

69 阅读3分钟

203.移除链表元素

题目链接/文章讲解/视频讲解::programmercarl.com/0203.%E7%A7…

思路

本题是链表的基础操作之一,链表删除操作关键步骤在于,通过绕过节点再删除该节点内存的方式达到删除的效果。Java有自带的回收机制,所以删除节点内存可以忽略。同时,删除头节点和删除中间节点的方法是不一样的,如果删除的是头节点,那就没有前序节点,无法进行“绕过”的操作。此时有两种方法,一种是单独判断是否是删除头节点,另一种是使用虚拟头节点让所有的节点都成为非头节点,从而达到结果。在这里我选用虚拟头节点的方式。

/**
 * 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) {
        if(head == null){
            return head;
        }
        ListNode dummyHead = new ListNode(-1, head);
        ListNode pre = dummyHead;
        ListNode cur = dummyHead.next;
        while(cur != null)
        {
            if(cur.val == val){
                pre.next = cur.next;
            }else{
                pre = cur;
            }
            cur = cur.next;
        }
        return dummyHead.next;
    }
}

707.设计链表

题目链接/文章讲解/视频讲解:programmercarl.com/0707.%E8%AE…

思路

class LinkedNode{
    int val;
    LinkedNode next;
    public LinkedNode(){};
    public LinkedNode(int val){this.val = val;}
}
class MyLinkedList {
    private int size; 
    private LinkedNode dummyHead;
    public MyLinkedList() {
        size = 0;
        dummyHead = new LinkedNode(-1);
    }
    
    public int get(int index) {
        if (index < 0 || index >= size) return -1;
        LinkedNode cur = dummyHead.next; 
        for (int i = 0; i < index; i++) {
            cur = cur.next;
        }
        return cur.val;
    }
    // 可以直接调用addAtIndex
    // public void addAtHead(int val) {
    //     addAtIndex(0, val);
    // }
    public void addAtHead(int val) {
        LinkedNode newHead = new LinkedNode(val);
        newHead.next = dummyHead.next;
        dummyHead.next = newHead;
        size++;
    }
​
    // 可以直接调用addAtIndex
    // public void addAtTail(int val) {
    //     addAtIndex(size, val);
    // }
    public void addAtTail(int val) {
        LinkedNode node = new LinkedNode(val);
        LinkedNode cur = dummyHead;
        while(cur.next != null)
        {
            cur = cur.next;
        }
        cur.next = node;
        size++;
​
    }
    
    public void addAtIndex(int index, int val) {
        if(index > size) return;
        if(index < 0) index = 0;
        LinkedNode pre = dummyHead;
        for(int i = 0; i < index; i++){
            pre = pre.next;
        }
        LinkedNode node = new LinkedNode(val);
        node.next = pre.next;
        pre.next = node;
        size++;
    }
    
    public void deleteAtIndex(int index) {
        if (index < 0 || index >= size) return;
        LinkedNode pre = dummyHead;
        for (int i = 0; i < index; i++) {
            pre = pre.next;
        }
        if (pre.next != null) {
            pre.next = pre.next.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);
 */

206.反转链表

题目链接/文章讲解/视频讲解:programmercarl.com/0206.%E7%BF…

思路

理解反转链表的核心是,如何改变每个节点的指向,即当前节点指向它之前的节点。开始时,我们有一个指向链表头部的指针cur。在反转过程中,我们逐个访问这个链表的每个节点,并将每个节点的next指针指向它的前一个节点。为了遍历这个链表,我们还需要额外引入一个temp节点,用于存储还未遍历的链表。整个过程就是在不断地更新节点间的连接关系,直到所有节点都重新指向了它们之前的节点。反转完成后,我们得到一个新的链表,其节点顺序与原始链表完全相反。这个过程不涉及新节点的创建,仅仅是改变现有节点间的连接方式。

代码随想录的动图更加直观:

img

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