持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第5天,点击查看活动详情
一、题目
struct ListNode {
int val;
ListNode *next = nullptr;
inline ListNode(int x, ListNode* next = nullptr) : val(x), next(next) { }
};
bool isPalindrome(ListNode* pHead) {
}
int main(int, char**)
{
ListNode p1(1);
ListNode p2(2);
ListNode p3(3);
ListNode p4(2);
ListNode p5(1);
p1.next = &p2;
p2.next = &p3;
p3.next = &p4;
p4.next = &p5;
p5.next = nullptr;
cout << (isPalindrome(&p1) ? "是回文" : "不是回文") << endl;
return 0;
}
二、分析
根据题意可知,我们需要判断字符串是否是回文,
回文的特点是从左右两头往中间遍历,结果相同,
但是从尾部出发,势必要先遍历一遍,效率太低。
难点一:
由特点可知,从中间向左右出发遍历,也可判断,
那关键点就在于获取中间点,此时需要分两种情况,
一种总数是偶数,一种总数是奇数。
难点二:
由于链表是单向,不能实现从右到左的方向,所以,
我们还需要对左边一半部分进行逆序处理。
三、模拟
-
创建两个遍历节点,速度差是两倍,这样一个跑完,另一个刚好跑一半
节点一 跑得快A
节点二 跑得慢B -
创建新的节点,链接跑的慢的节点跑过的路
节点三 新表头
老表头指向新表头的子节点
新表头指向老表头
老表头也走一步 -
判断总数的奇偶性 新表头和跑得慢都是一步一步的跑,所以会指向同一节点
因为跑得快是两步两步的跑,所以奇数肯定会跑出界,此时,跑得慢就刚好指向中间节点,新表头也会链到中间节点,偶数就会指向中间偏左,就需要再走一步
如果 跑得快存在 跑得慢再跑一步
- 循环迭代比较新表头和跑得慢的值是否相等
四、实现
bool isPalindrome(ListNode* pHead) {
if(pHead == nullptr || pHead->next == nullptr) return true;
ListNode* rabbit = pHead;
ListNode* tortoise = pHead;
ListNode* head = pHead;
ListNode cur(0);
while(rabbit != nullptr && rabbit->next != nullptr){
rabbit = rabbit->next->next;
tortoise = tortoise->next;
ListNode* temp = head->next;
head->next = cur.next;
cur.next = head;
head = temp;
}
if(rabbit){
tortoise = tortoise->next;
}
while(tortoise){
if(tortoise->val != cur.next->val){
return false;
}
tortoise = tortoise->next;
cur.next = cur.next->next;
}
return true;
}
五、结言
利用了前面做过的逆序,总体难度不高
创作不易,留个赞再走吧!如果对文章内容有任何指正,欢迎评论!