想法一
先找中间结点,如果为偶数,则指向第二个结点,再把后半段逆置,最后从头进行比对
中间节点:
这段代码在找中间结点那题写过,所以直接拷贝过来
struct ListNode* middleNode(struct ListNode* head) { //要求只遍历一遍链表 struct ListNode* slow = head;//一次走一格 struct ListNode* fast = head;//一次走两格 while (fast->next) { slow = slow->next; fast = fast->next->next; if (!fast) { break; } } return slow; }
逆置:
这段代码也在反转链表时写过,所以直接拷贝过来
struct ListNode* reverseList(struct ListNode* head) { struct ListNode* cur = head; struct ListNode* rhead = NULL; while (cur) { //头插 struct ListNode* next = cur->next; cur->next = rhead; rhead = cur; cur = next; } return rhead; }
最后,比对才是本题需要做的事情。如果head结点的值与rmid不相等,则不是回文,如果相等,则同时往后一个结点,如果循环结束还没return false,那就证明链表是回文的,return true
bool isPalindrome(struct ListNode* head) { struct ListNode* mid = middleNode(head); struct ListNode* rmid = reverseList(mid); while (rmid) { if (head->val != rmid->val) { return false; } else { head = head->next; rmid = rmid->next; } } return true; }
可能有小伙伴会担心,是奇数个节点的时候,好像head比rmid少一个节点啊?其实,不用担心,因为rmid前的节点还是指向结尾的,如图
所以最后两个指针会共同走到最后一个节点
总结,这是一道糅合了之前多种方法(可以偷懒,cv大法)的题
完整代码:
struct ListNode* reverseList(struct ListNode* head) { struct ListNode* cur = head; struct ListNode* rhead = NULL; while (cur) { //头插 struct ListNode* next = cur->next; cur->next = rhead; rhead = cur; cur = next; } return rhead; } struct ListNode* middleNode(struct ListNode* head) { //要求只遍历一遍链表 struct ListNode* slow = head;//一次走一格 struct ListNode* fast = head;//一次走两格 while (fast->next) { slow = slow->next; fast = fast->next->next; if (!fast) { break; } } return slow; } bool isPalindrome(struct ListNode* head) { struct ListNode* mid = middleNode(head); struct ListNode* rmid = reverseList(mid); while (rmid) { if (head->val != rmid->val) { return false; } else { head = head->next; rmid = rmid->next; } } return true; }