leetcode 笔记刷题(三)206 反转链表

剑指 Offer 24. 反转链表

定义一个函数,输入一个链表的头节点,反转该链表并输出反转后链表的头节点。

示例:

输入: 1->2->3->4->5->NULL
输出: 5->4->3->2->1->NULL
 

限制:

0 <= 节点个数 <= 5000

注意:本题与主站 206 题相同:https://leetcode-cn.com/problems/reverse-linked-list/

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode(int x) : val(x), next(NULL) {}
 * };
 */
class Solution {
public:
    ListNode* reverseList(ListNode* head) {

    }
};

题解一

在遍历链表时,将当前节点的 \textit{next}next 指针改为指向前一个节点。由于节点没有引用其前一个节点,因此必须事先存储其前一个节点。在更改引用之前,还需要存储后一个节点。最后返回新的头引用。


#include <iostream>

using namespace std;

//Definition for singly - linked list.
struct ListNode {
	int val;
	ListNode *next;
	ListNode(int x) : val(x), next(NULL) {}
};

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;
	}
};

/*打印链表*/
void printList(ListNode* head)
{
	ListNode* phead = head;
	while (phead != NULL)
	{
		cout << phead->val << " ";
		phead = phead->next;
	}
	cout << "\n";
}


int main()
{
	//链表赋值
	int a[5] = {1,2,3,4,5};
	ListNode *La = new ListNode(a[0]);
	ListNode* phead = La;

	for (int i = 1; i < 5; i++)
	{
		ListNode* newnode = new ListNode(a[i]);
		phead->next = newnode;//并将其赋值给La
		phead = newnode;
	} //链表赋值

	Solution sln;
	printList(La);
	ListNode* Lc = sln.reverseList(La);
	printList(Lc);
	return 0;
}

复杂度分析

  • 时间复杂度:O(n),其中 n 是链表的长度。需要遍历链表一次。

  • 空间复杂度:O(1)。

好理解的双指针
定义两个指针: prepre 和 curcur ;prepre 在前 curcur 在后。
每次让 prepre 的 nextnext 指向 curcur ,实现一次局部反转
局部反转完成之后, prepre 和 curcur 同时往前移动一个位置
循环上述过程,直至 prepre 到达链表尾部

解题二

简洁的递归
使用递归函数,一直递归到链表的最后一个结点,该结点就是反转后的头结点,记作 retret .
此后,每次函数在返回的过程中,让当前结点的下一个结点的 nextnext 指针指向当前节点。
同时让当前结点的 nextnext 指针指向 NULLNULL ,从而实现从链表尾部开始的局部反转
当递归函数全部出栈后,链表反转完成。

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

解题三

妖魔化的双指针
原链表的头结点就是反转之后链表的尾结点,使用 headhead 标记 .
定义指针 curcur,初始化为 headhead .
每次都让 headhead 下一个结点的 nextnext 指向 curcur ,实现一次局部反转
局部反转完成之后,curcur 和 headhead 的 nextnext 指针同时 往前移动一个位置
循环上述过程,直至 curcur 到达链表的最后一个结点 .

class Solution {
public:
    ListNode* reverseList(ListNode* head) {
        if (head == NULL) { return NULL; }
        ListNode* cur = head;
        while (head->next != NULL) {
            ListNode* t = head->next->next;
            head->next->next = cur;
            cur = head->next;
            head->next = t;
        }
        return cur;
    }
};

面试官给了一张白纸,然后直接手写了一道题:反转链表

就4个字,不像leetcode上面还有输入输出示例,以及最关键的链表的结构:链表用一个结构体表示,包含两个成员值val和指针next,以及一个构造函数。

猜你喜欢

转载自blog.csdn.net/juluwangriyue/article/details/115218620