LeetCode刷题Day04——链表(设计单/双链表、移除、翻转、交换链表节点)

简介: 迭代法:首先创建一个临时的节点p用于遍历链表,其开始可以指向头节点,也可以让其next节点指向头节点(如果p指向头节点则while循环的判断条件是p!=null,反之则是p.next!=null),随后p不断地向后移动,在这个过程中进行要求的操作。如果结果要返回头指针,可以实现创建一个节点让其next指向头指针。如果是要删除元素,那么需要拥有前一个节点的指针,让其指向要删除的元素的下一个元素,所以此时则不能让p指向头节点,而应该是让next去指向,即判断的是下一个元素的值,这样才能够实现删除。如果是要翻转链表,那么需要不断改变指针的方向,即让next等于之前的元素,所以需要一个变量prev

对于链表的操作大多有迭代和递归两种解决方法:

迭代法:首先创建一个临时的节点p用于遍历链表,其开始可以指向头节点,也可以让其next节点指向头节点((如果p指向头节点则while循环的判断条件是p!=null,反之则是p.next!=null),随后p不断地向后移动,在这个过程中进行要求的操作。如果结果要返回头指针,可以实现创建一个节点让其next指向头指针。

  • 如果是要删除元素,那么需要拥有前一个节点的指针,让其指向要删除的元素的下一个元素,所以此时则不能让p指向头节点,而应该是让next去指向,即判断的是下一个元素的值,这样才能够实现删除。
  • 如果是要翻转链表,那么需要不断改变指针的方向,即让next等于之前的元素,所以需要一个变量prev记录之前的元素,在循环内先将下一个元素保存到next变量之后再改变指针的指向,指向prev,然后将prev更改为p,将p更改为next,这样就能顺利遍历链表。
  • 递归法:链表的递归实际上就是将链表拆为一个一个的子链表,不断缩小链表的长度,当到链表的最后一位(即p或p.next=null时),递归就到达了最底层,这时直接返回null或head。每一层递归传递给下一层的参数一般时子链表的头指针,拿到头指针后进行操作,之后根据题目要求进行操作并且返回上一层所需要的结果,一般是处理后新的头指针,用于给上一层的尾元素进行连接(比如进行交换顺序头指针发生改变时),或者一直返回最底层的指针(进行翻转头指针没有发生改变时(由于子链表的顺序没有改变,上一层可以直接拿到正确的下一个元素所以不需要下一层返回))

一、移出链表元素

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

/**
 * <pre>
 * <p>可以采用迭代,不断判断下一个节点是否要删除;或者采用递归,每次获取子链表的head,如果头节点的值如果等于val就说明返回的是子链表的头</p>
 * </pre>
 *
 * @author <a href="https://github.com/kil1ua">Ken-Chy129</a>
 * @date 2023/1/5 10:45
 */
public class 移出链表元素203 {
    // 迭代
    public ListNode removeElements(ListNode head, int val) {
        ListNode res = new ListNode();
        res.next = head;
        ListNode p = res;
        while (p.next != null) {
            if (p.next.val == val) {
                p.next = p.next.next;
            } else { 
                p = p.next;
            }
        }
        return res.next;
    }
    // 递归
    public ListNode removeElements2(ListNode head, int val) {
        if (head == null) {
            return null;
        }
        head.next = removeElements2(head.next, val); // 每次删除子链表,返回子链表的头
        return head.val == val ? head.next : head;
    }
}
class ListNode {
    int val;
    ListNode next;
    ListNode() {}
    ListNode(int val) { this.val = val; }
    ListNode(int val, ListNode next) { this.val = val; this.next = next; }
}


二、设计链表

题目链接:707.设计链表


/**
 * <pre>
 * <p>链表的设计:单链表和双链表</p>
 * </pre>
 *
 * @author <a href="https://github.com/kil1ua">Ken-Chy129</a>
 * @date 2023/1/5 11:29
 */
// 单链表
class MyLinkedList {
    private int size;
    private MyListNode head;
    public MyLinkedList() {
        size = 0;
        head = new MyListNode(0);
    }
    public int get(int index) {
        if (index < 0 || index >= size) {
            return -1;
        }
        MyListNode p = head;
        for (int i=0; i<=index; i++) {
            p = p.next;
        }
        return p.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 < 0 || index > size) {
            return;
        }
        MyListNode p = head;
        for (int i=0; i<index; i++) {
            p = p.next;
        }
        MyListNode newNode = new MyListNode(val);
        newNode.next = p.next;
        p.next = newNode;
        size++;
    }
    public void deleteAtIndex(int index) {
        if (index < 0 || index >= size) {
            return;
        }
        MyListNode p = head;
        for (int i=0; i<index; i++) {
            p = p.next;
        }
        p.next = p.next.next;
        size--;
    }
}
class MyListNode {
    int val;
    MyListNode next;
    public MyListNode() {
    }
    public MyListNode(int val) {
        this.val = val;
    }
    public MyListNode(int val, MyListNode next) {
        this.val = val;
        this.next = next;
    }
}
// 双链表
class BiLinkedList {
    private int size;
    private BiListNode head;
    private BiListNode tail;
    public BiLinkedList() {
        size = 0;
        head = new BiListNode(0);
        tail = new BiListNode(0);
        head.next = tail;
        tail.prev = head;
    }
    public int get(int index) {
        if (index < 0 || index >= size) {
            return -1;
        }
        BiListNode p;
        if (index < size/2) {
            p = head;
            for (int i=0; i<=index; i++) {
                p = p.next;
            }
        } else {
            p = tail;
            for (int i=0; i<size-index; i++) {
                p = p.prev;
            }
        }
        return p.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 < 0 || index > size) {
            return;
        }
        BiListNode p;
        if (index < size/2) {
            p = head;
            for (int i=0; i<index; i++) {
                p = p.next;
            }
        } else {
            p = tail;
            for (int i=0; i<=size-index; i++) {
                p = p.prev;
            }
        }
        BiListNode newNode = new BiListNode(val);
        newNode.next = p.next;
        newNode.prev = p;
        p.next.prev = newNode;
        p.next = newNode;
        size++;
    }
    public void deleteAtIndex(int index) {
        if (index < 0 || index >= size) {
            return;
        }
        BiListNode p;
        if (index < size/2) {
            p = head;
            for (int i=0; i<index; i++) {
                p = p.next;
            }
        } else {
            p = tail;
            for (int i=0; i<=size-index; i++) {
                p = p.prev;
            }
        }
        p.next = p.next.next;
        p.next.prev = p;
        size--;
    }
}
class BiListNode {
    int val;
    BiListNode next;
    BiListNode prev;
    public BiListNode() {
    }
    public BiListNode(int val) {
        this.val = val;
    }
}



三、翻转链表

题目链接:206.翻转链表


/**
 * <pre>
 * <p>翻转链表:迭代或递归</p>
 * </pre>
 *
 * @author <a href="https://github.com/kil1ua">Ken-Chy129</a>
 * @date 2023/1/5 13:39
 */
public class 翻转链表206 {
    // 迭代法
    public ListNode reverseList(ListNode head) {
        ListNode prev=null, p=head, next;
        while (p != null) {
            next = p.next;
            p.next = prev;
            prev = p;
            p = next;
        }
        return prev;
    }
    // 递归法
    public ListNode reverseList2(ListNode head) {
        if (head == null || head.next == null) { // head == null 是用于0长度的链表直接返回
            return head; // 遍历到最后一个节点则返回,这个就是翻转后链表的头
        }
        ListNode newHead = reverseList2(head.next);
        // 如果是1->2->3->...->k->k+1->...->k+n
        // 执行到k时变为1->2->3->...->k->k+1<-...<-k+n
        // 那么k的next是k+1,需要将k+1的next改为k
        head.next.next = head;
        // 将k的next置为null,不然会成环,k指向k+1而k+1指向k
        head.next = null;
        return newHead;
    }
}



四、两两交换链表中的节点

题目链接:24.两两交换链表中的节点


/**
 * <pre>
 * <p>可以采用迭代也可以采用递归</p>
 * </pre>
 *
 * @author <a href="https://github.com/kil1ua">Ken-Chy129</a>
 * @date 2023/1/5 14:58
 */
public class 两两交换链表中的节点24 {
    public ListNode swapPairs(ListNode head) {
        ListNode p = new ListNode(), res = p;
        p.next = head;
        while (p.next != null  && p.next.next != null) {
            ListNode first = p.next, second = p.next.next;
            first.next = second.next;
            second.next = first;
            p.next = second;
            p = first;
        }
        return res.next;
    }
    // 递归
    public ListNode swapPairs2(ListNode head) {
        if (head == null || head.next == null) {
            return head;
        }
        ListNode next = swapPairs(head.next.next);
        ListNode second = head.next;
        head.next = next;
        second.next = head;
        return second;
    }
}
相关文章
|
2月前
|
机器学习/深度学习 人工智能 自然语言处理
280页PDF,全方位评估OpenAI o1,Leetcode刷题准确率竟这么高
【10月更文挑战第24天】近年来,OpenAI的o1模型在大型语言模型(LLMs)中脱颖而出,展现出卓越的推理能力和知识整合能力。基于Transformer架构,o1模型采用了链式思维和强化学习等先进技术,显著提升了其在编程竞赛、医学影像报告生成、数学问题解决、自然语言推理和芯片设计等领域的表现。本文将全面评估o1模型的性能及其对AI研究和应用的潜在影响。
75 1
|
3月前
LeetCode第二十四题(两两交换链表中的节点)
这篇文章介绍了LeetCode第24题的解法,即如何通过使用三个指针(preNode, curNode, curNextNode)来两两交换链表中的节点,并提供了详细的代码实现。
34 0
LeetCode第二十四题(两两交换链表中的节点)
|
3月前
Leetcode第十九题(删除链表的倒数第N个节点)
LeetCode第19题要求删除链表的倒数第N个节点,可以通过快慢指针法在一次遍历中实现。
50 0
Leetcode第十九题(删除链表的倒数第N个节点)
05_删除链表的倒数第N个节点
05_删除链表的倒数第N个节点
|
3月前
(剑指offer)18、删除链表的节点—22、链表中倒数第K个节点—25、合并两个排序的链表—52、两个链表的第一个公共节点(2021.12.07)
(剑指offer)18、删除链表的节点—22、链表中倒数第K个节点—25、合并两个排序的链表—52、两个链表的第一个公共节点(2021.12.07)
61 0
04_两两交换链表中的节点
04_两两交换链表中的节点
|
7月前
|
存储 SQL 算法
LeetCode力扣第114题:多种算法实现 将二叉树展开为链表
LeetCode力扣第114题:多种算法实现 将二叉树展开为链表
|
7月前
|
存储 SQL 算法
LeetCode 题目 86:分隔链表
LeetCode 题目 86:分隔链表
|
7月前
|
存储 算法 Java
【经典算法】Leetcode 141. 环形链表(Java/C/Python3实现含注释说明,Easy)
【经典算法】Leetcode 141. 环形链表(Java/C/Python3实现含注释说明,Easy)
69 2
|
8月前
<数据结构>五道LeetCode链表题分析.环形链表,反转链表,合并链表,找中间节点.
<数据结构>五道LeetCode链表题分析.环形链表,反转链表,合并链表,找中间节点
86 1