Day14(链表)——LeetCode234.回文链表141.环形链表
1前言
这几天脑子真转不动,本想刷点简单题养养脑子,结果发现简单题也想不到,只是看答案好理解了。。。
2 LeetCode234.回文链表(LeetCode234)
2.1 题目描述
即判断链表是否为回文链表,回文链表即链表的数值正向遍历与反向遍历结果一致。具体示例如下:
2.2 问题分析与解决
简单的思路就是遍历链表,将链表的值放入数组中判断,但是这样需要 O ( n ) O(n) O(n)的空间。如果使用 O ( 1 ) O(1) O(1)的空间和 O ( n ) O(n) O(n)的时间如何解决?
一个思路可以用两个指针分别从头尾遍历,但是单向链表无法逆向遍历,因此该思路行不通。观察回文链表,可以发现其关于中间对称,因此我们可以先找到中间的节点,判断中间节点分成的两部分是否对称,由于我们仍无法逆序遍历中间前半部分,因此需要将中间后半部分反转,判断其与中间前半部分是否相同即可。
因此我们的思路是,对于 n n n个节点的链表,先找到第 ⌊ n 2 ⌋ \lfloor\frac{n}{2}\rfloor ⌊2n⌋个节点:
可以定义两个指针,一个一次走一步(慢指针),一个一次走两步(快指针),当快指针走到最后时,慢指针正好走到中间。
然后将中间后面的链表进行反转,使用头插法即可,然后遍历反转的链表和原链表的前半部分,看二者是否对应相等即可。
具体代码如下:
/*** 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) {}* };*/
class Solution {
public:bool isPalindrome(ListNode* head) {//找到中间节点ListNode* fast=head,* slow=head;while(fast!=NULL&&fast->next!=NULL){fast=fast->next->next;slow=slow->next;}//反转ListNode* newhead=NULL,*tmp=slow;while(tmp!=NULL){ListNode* tmp1=tmp->next;tmp->next=newhead;newhead=tmp;tmp=tmp1;}//判断是否是回文链表while(newhead!=NULL){if(head->val!=newhead->val) return false;head=head->next;newhead=newhead->next;}return true;}
};
3 LeetCode141.环形链表
3.1 题目描述
即判断链表是否包含环。具体描述与示例如下:
3.2 问题分析与解决
一个简单的思路是遍历链表,记录每个节点出现的次数,若某个节点出现两次则判断有环,否则判断无环。但这样需要 O ( n ) O(n) O(n)的空间(哈希表)。我们仍需思考如何使用 O ( 1 ) O(1) O(1)的时间来解决。
受上述快慢指针影响,仍可以定义上述的快慢指针,若链表有环,则快指针肯定会“套圈”慢指针,即快指针与慢指针指向同一个节点;若无环,则快指针先遍历结束。
根据这个思路很容易实现代码:
/*** Definition for singly-linked list.* struct ListNode {* int val;* ListNode *next;* ListNode(int x) : val(x), next(NULL) {}* };*/
class Solution {
public:bool hasCycle(ListNode *head) {ListNode* fast=head,* slow=head;while(fast!=NULL&&fast->next!=NULL){fast=fast->next->next;slow=slow->next;if(slow==fast) return true;}return false;}
};