• LeetCode206


    题目链接

    https://leetcode-cn.com/problems/reverse-linked-list/description/

    题目分析

    • 要求:反转一个单向链表
    • 代码模板里的ListNode给了3个构造函数,明显是方便我们构造结点用的(如果要new,最好要delete)
    • 可以迭代实现,也可以递归实现

    题解一:递归

    思路

    递归算法中有两个重要概念:递归表达式和递归出口,这一点似乎主要是在算法设计与分析课程上学得的。

    • 递归出口

      递归出口越小越好,出口应该考虑到边界条件

    • 递归表达式

      递归表达式是将链表分为两部分A和B,B用递归表达式递归处理,然后再将A和B“拼接”起来

    过程经历

    1. 找错递归出口然后修改
    2. 未处理只有0或1个结点的边界情况,修改后得到代码一
    3. 代码一未将递归出口最小化,修改后得到代码二
    4. 代码二未利用一点(链表B反转后,原先的头结点已经是尾结点了,不需要通过遍历寻找尾结点),因此存在多余的遍历,修改后得到代码三

    代码一

    这一版不太优美,最后一层没用递归(递归应该最大化,出口应该最小化),而是手动实现了就又改了一版,可以再往下看(代码二)。

    // Problem: LeetCode 206
    // URL: https://leetcode.com/problems/reverse-linked-list/description/
    // Tags: Linked List Recursion Iteration
    // Difficulty: Easy
    
    #include <iostream>
    using namespace std;
    
    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){}
    };
    
    class Solution{
    public:
        ListNode *reverseList(ListNode *head)
        {
            // 边界:when there is no node or there is only 1 node, then it's no need to reverse,just return the input
            if(nullptr == head || nullptr == head->next){
                return head;
            }
            // 递归出口(recursive export),when there are only 2 nodes
            if(nullptr == head->next->next){
                ListNode *ptrA = head;
                ListNode *ptrB = head->next;
                ptrB->next = ptrA;
                ptrA->next = nullptr;
                return ptrB;
            }
    
    
            // 以下为递归表达式
    
            // devide the nodes into A(the original head) and B(the nodes except the original head).
            ListNode *ptrA = head;  // A:原先的head
            ListNode *ptrB = reverseList(head->next);  // B:将原先head以外的结点逆序并返回其head
    
            // look for the tail of B,寻找B的尾巴
            ListNode* tailB = ptrB;  
            while (tailB->next != nullptr){tailB = tailB->next;}
    
            // 将A连接到B后面并将A设置为尾结点
            tailB->next = ptrA;
            ptrA->next = nullptr;
    
            // 返回链表B
            return ptrB;
        }
    };
    
    int main()
    {
        // system("pause");
        return 0;
    }
    

    代码二

    // Problem: LeetCode 206
    // URL: https://leetcode.com/problems/reverse-linked-list/description/
    // Tags: Linked List Recursion Iteration
    // Difficulty: Easy
    
    #include <iostream>
    using namespace std;
    
    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){}
    };
    
    class Solution{
    public:
        ListNode *reverseList(ListNode *head)
        {
            // 边界:when there is no node, then it's no need to reverse,just return the input
            if (nullptr == head)
            {
                return head;
            }
    
            // 递归出口(recursive export),when there is only 1 nodes
            if (nullptr == head->next)
            {
                return head;
            }
    
            // devide the nodes into A(the original head) and B(the nodes except the original head).
            ListNode *ptrA = head; // A:原先的head
            ListNode *ptrB = reverseList(head->next); // B:将原先head以外的结点逆序并返回其head
    
            // look for the tail of B,寻找B的尾巴
            ListNode *tailB = ptrB;
            while (tailB->next != nullptr)
            {
                tailB = tailB->next;
            }
    
            // 将A连接到B后面并将A设置为尾结点
            tailB->next = ptrA;
            ptrA->next = nullptr;
    
            // 返回链表B
            return ptrB;
        }
    };
    
    int main()
    {
        // system("pause");
        return 0;
    }
    

    代码三

    第二天看了题解之后,发现我自己忽略了一点:

    ListNode *ptrB = reverseList(head->next);运行后,链表B反转前的第一个结点(即head->next)已经是链表B反转后的最后一个结点,所以不需要再寻找B的尾结点了。

    修改后代码如下:

    // Problem: LeetCode 206
    // URL: https://leetcode.com/problems/reverse-linked-list/description/
    // Tags: Linked List Recursion Iteration
    // Difficulty: Easy
    
    #include <iostream>
    using namespace std;
    
    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){}
    };
    
    class Solution{
    public:
        ListNode *reverseList(ListNode *head)
        {
            // 边界:when there is no node, then it's no need to reverse,just return the input
            if (nullptr == head)
            {
                return head;
            }
    
            // 递归出口(recursive export),when there is only 1 nodes
            if (nullptr == head->next)
            {
                return head;
            }
    
            // devide the nodes into A(the original head) and B(the nodes except the original head).
            ListNode *ptrA = head; // A:原先的head
            ListNode *ptrB = reverseList(head->next); // B:将原先head以外的结点逆序并返回其head,此时head->next已经为最后一个结点
    
            // 将A连接到B后面并将A设置为尾结点
            head->next->next = ptrA;
            ptrA->next = nullptr;
    
            // 返回链表B
            return ptrB;
        }
    };
    
    int main()
    {
        // system("pause");
        return 0;
    }
    

    题解二:迭代

    思路

    其实就是头插法,另外要注意这道题里中链表的头结点的val是有意义的,所以最后要new出来的头结点delete掉,并返回其next。

    代码一

    这份代码是没有修改原链表的结构的,而是基于原链表new了一个新链表(是原链表的逆序)

    // Problem: LeetCode 206
    // URL: https://leetcode.com/problems/reverse-linked-list/description/
    // Tags: Linked List Recursion Iteration
    // Difficulty: Easy
    
    #include <iostream>
    using namespace std;
    
    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){}
    };
    
    class Solution{
    public:
        ListNode *reverseList(ListNode *head)
        {
            // 创建新链表
            ListNode* newHead = new ListNode(-1);
            while (head != nullptr){
                ListNode *tempNodePtr = new ListNode(head->val, head->next);
                tempNodePtr->next = newHead->next;
                newHead->next = tempNodePtr;
                // 取下一个结点
                head = head->next;
            }
    
            // 释放无用的头结点并返回真正的头结点
            ListNode* ret = newHead->next;
            delete newHead;
            return ret;
        }
    };
    
    int main()
    {
        // system("pause");
        return 0;
    }
    

    代码二

    这份代码修改了原链表的结构,直接利用了原链表的结点

    // Problem: LeetCode 206
    // URL: https://leetcode.com/problems/reverse-linked-list/description/
    // Tags: Linked List Recursion Iteration
    // Difficulty: Easy
    
    #include <iostream>
    using namespace std;
    
    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){}
    };
    
    class Solution{
    public:
        ListNode *reverseList(ListNode *head)
        {
            // 创建新链表
            ListNode* newHead = new ListNode(-1);
            while (head != nullptr){
                ListNode* next = head->next;
                head->next = newHead->next;
                newHead->next = head;
                // 取下一个结点
                head = next;
            }
    
            // 释放无用的头结点并返回真正的头结点
            ListNode* ret = newHead->next;
            delete newHead;
            return ret;
        }
    };
    
    int main()
    {
        // system("pause");
        return 0;
    }
    

    作者:@臭咸鱼

    转载请注明出处:https://www.cnblogs.com/chouxianyu/

    欢迎讨论和交流!


  • 相关阅读:
    Soap 教程
    MAC mysql install
    PHP date
    MAC 终端terminal颜色
    MAC 终端颜色设置
    MAC brew软件安装
    PHP iconv函数
    Java----前端验证之验证码额实现
    Java---Ajax在Struts2框架的应用实例
    Java基础—标识符及命名规范
  • 原文地址:https://www.cnblogs.com/chouxianyu/p/13284071.html
Copyright © 2020-2023  润新知