码迷,mamicode.com
首页 > 其他好文 > 详细

LeetCode206

时间:2020-07-11 17:17:33      阅读:55      评论:0      收藏:0      [点我收藏+]

标签:std   部分   NPU   逆序   遍历   etc   边界条件   tps   lis   

题目链接

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/

欢迎讨论和交流!


LeetCode206

标签:std   部分   NPU   逆序   遍历   etc   边界条件   tps   lis   

原文地址:https://www.cnblogs.com/chouxianyu/p/13284071.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!