Bootstrap

C++/JavaScript ⭐算法OJ⭐链表的反转

题目描述

Given the head of a singly linked list, reverse the list, and return the reversed list.

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode() : val(0), next(nullptr) {}
 *     ListNode(int x) : val(x), next(nullptr) {}
 *     ListNode(int x, ListNode *next) : val(x), next(next) {}
 * };
 */
/**
 * Definition for singly-linked list.
 * function ListNode(val, next) {
 *     this.val = (val===undefined ? 0 : val)
 *     this.next = (next===undefined ? null : next)
 * }
 */

我们分别用迭代递归两种方法来实现单链表的反转。

1. 迭代法

迭代法的思路是通过遍历链表,逐个改变节点的指向,最终实现链表的反转。

class Solution {
public:
    ListNode* reverseList(ListNode* head) {
        ListNode* prev = nullptr;  // 前一个节点
        ListNode* curr = head;     // 当前节点
        while (curr) {
            ListNode* next = curr->next;  // 保存下一个节点
            curr->next = prev;  // 当前节点指向前一个节点
            prev = curr;        // 前一个节点移动到当前节点
            curr = next;       // 当前节点移动到下一个节点
        }
        return prev;  // 返回新的头节点
    }
};
/**
 * @param {ListNode} head
 * @return {ListNode}
 */
var reverseList = function(head) {
    let prev = null;
    let curr = head;
    while (curr) {
        const next = curr.next;
        curr.next = prev;
        prev = curr;
        curr = next;
    }
    return prev;
};

解释:

  • prev 用于保存当前节点的前一个节点,初始为 None
  • curr 是当前节点,初始为链表的头节点 head
  • 在循环中,我们逐个改变节点的指向,直到遍历完整个链表。
  • 最后返回 prev,它将成为反转后链表的新头节点。

2. 递归法

class Solution {
public:
    ListNode* reverseList(ListNode* head) {
        // 递归终止条件:链表为空或只有一个节点
        if (!head || !head->next) {
            return head;
        }
        
        // 递归反转剩余部分
        ListNode* newHead = reverseList(head->next);
        
        // 将当前节点的下一个节点指向自己
        head->next->next = head;
        head->next = nullptr;  // 断开原来的指向
        
        return newHead;  // 返回新的头节点
    }
};
/**
 * @param {ListNode} head
 * @return {ListNode}
 */
var reverseList = function(head) {
    if (!head || !head.next) {
        return head;
    }
    var newHead = reverseList(head.next);
    head.next.next = head;
    head.next = null;
    return newHead;
};

解释:

  • 递归终止条件是链表为空或只有一个节点,直接返回当前节点。
  • 递归调用 reverseList(head->next),反转剩余部分的链表。
  • 将当前节点的下一个节点指向自己(即 head->next->next = head),并断开原来的指向(head->next = nullptr)。
  • 返回新的头节点 newHead。

总结

  • 迭代法:通过循环逐个改变节点的指向,空间复杂度为 O(1)
  • 递归法:通过递归从链表末尾开始反转,空间复杂度为 O(n)(递归调用栈的深度)。

两种方法都可以实现链表的反转,选择哪种方法取决于具体需求和场景。

;