LeetCode :206.反转链表

题目

反转一个单链表。

示例

输入:

1->2->3->4->5->NULL

输出:

5->4->3->2->1->NULL

解法探析

解法 1:迭代法

思路分析

在遍历链表时,将当前结点的 next 指针改为指向其前一个结点。由于结点不会指向前一个结点,因此必须先存储其前一个结点。在更改指向之前,还需要另外一个指针来存储后一个结点。最后,返回新的头指针。

代码实现

C实现:

struct ListNode {
    int val;
    struct ListNode* next;
};

struct ListNode* reverseList(struct ListNode* head)
{
    struct ListNode* node = head;               // 当前指针,指向当前遍历到的结点
    struct ListNode* prev = NULL;               // 前驱指针,指向当前结点的前一个结点
    struct ListNode* reverseHead = NULL;        // 新的头指针,指向反转后链表的头结点,即原始链表的尾结点

    // 若当前指针不为 NULL
    while (node != NULL) {
        struct ListNode* pNext = node->next;    // 后继指针,指向当前结点的后一个结点

        if (pNext == NULL) {                    // 若后继指针为 NULL,则已到链表的末尾,新的头指针等于当前指针
            reverseHead = node;
        }

        node->next = prev;                      // 当前结点的 next 指针指向前驱结点
        
        prev = node;                            // 更新前驱指针
        node = pNext;                           // 当前指针后移
    }

    return reverseHead;
}

C++实现:

struct ListNode {
      int val;
      ListNode* next;
      ListNode(int x) : val(x), next(nullptr) {}
};

class Solution {
public:
    ListNode* reverseList(ListNode* head) {
        ListNode* node = head;
        ListNode* prev = nullptr;
        ListNode* reverseHead = nullptr;

        while (node != nullptr) {
            ListNode* pNext = node->next;

            if (pNext == nullptr) {
                reverseHead = node;
            }

            node->next = prev;

            prev = node;
            node = pNext;
        }
        return reverseHead;
    }
};

GO实现:

type ListNode struct {
    Val int
    Next *ListNode
}

func reverseList(head *ListNode) *ListNode {
    node := head
    var prev *ListNode = nil
    var reverseHead *ListNode = nil
    
    for node != nil {

        pNext := node.Next

        if pNext == nil {
            reverseHead = node
        }

        node.Next = prev

        prev = node
        node = pNext
    }

    return reverseHead
}

复杂度分析

时间复杂度:\(O(n)\)(假设 n 为链表的长度)
空间复杂度:\(O(1)\)

动态图解

解法 2:递归法

思路分析

递归法稍微复杂了一些,其关键在于反向工作。假设链表是 1->2->3->4->5->NULL,则递归过程如下:

1.底层最后一个 reverseList(5) 返回了 5 这个结点。
2.在 reverseList(4) 中,reverseHead 为 5,head 为4,head->next->next = head 相当于 5->4。
3.此时结点的情况为 4->5->4,为了防止链表循环,使用 head->next = null 切断 4->5 这一条,最后返回:5->4->NULL。
4.返回到上一层 reverseList(3),最后返回:5->4->3->NULL。
5.reverseList(2)、reverseList(1) 依次类推,最后返回:5->4->3->2->1->NULL。

代码实现

C实现:

// 定义单链表的结点类型
struct ListNode {
    int val;
    struct ListNode* next;
};

struct ListNode* reverseList(struct ListNode* head)
{
    // 若当前结点为 NULL,或者下一个结点为 NULL,则递归终止
    if (head == NULL || head->next == NULL) {
        return head;
    }

    // 结点 reverseHead 就是反转链表的头结点 
    struct ListNode* reverseHead = reverseList(head->next);

    // 将反转链表的尾结点(head->next)的 next 指向当前即将反转的结点
    // 如果链表是 1->2->3->4->5,那么此时的 reverseHead 就是5,
    // 而 head 是4,head 的下一个是5,下下一个是空,所以 head->next->next 就是5->4
    head->next->next = head;

    // 防止链表循环,将head->next置为 NULL
    head->next = NULL;

    // 每层递归函数都返回reverseHead,也就是最后一个结点
    return reverseHead;
}

C++实现:

struct ListNode {
      int val;
      ListNode* next;
      ListNode(int x) : val(x), next(nullptr) {}
};

class Solution {
public:
    ListNode* reverseList(ListNode* head) {
        if (head == nullptr || head->next == nullptr) {
            return head;
        }

        ListNode* reverseHead = reverseList(head->next);
        head->next->next = head;
        head->next = NULL;
        return reverseHead;
    }
};

GO实现:

type ListNode struct {
    Val int
    Next *ListNode
}

func reverseList(head *ListNode) *ListNode {
    if head == nil || head.Next == nil {
        return head
    }

    reverseHead := reverseList(head.Next)

    head.Next.Next = head
    head.Next = nil

    return reverseHead
}

复杂度分析

时间复杂度:\(O(n)\)(假设 n 为链表的长度)
空间复杂度:\(O(n)\)(由于使用递归,会使用隐式栈空间,递归深度可能会达到 n 层)


个人主页:

www.codeapes.cn

posted @ 2020-02-05 16:29  Codeapes  阅读(156)  评论(0编辑  收藏  举报