题目
给你一个单链表的头节点 head ,请你判断该链表是否为回文链表。如果是,返回 true ;否则,返回 false 。
示例 1:
输入:head = [1,2,2,1]
输出:true
示例 2:
输入:head = [1,2]
输出:false
提示:
链表中节点数目在范围[1, 105] 内
0 <= Node.val <= 9
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/palindrome-linked-list
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
题解
判断是否为回文链表:
第一种方法:
- 首先找到中间节点
- 将中间节点后面的链表进行反转
- 将head节点和后面反转的链表进行val(值)比较,判断是否相等
第二种方法:
- 使用递归进行后序遍历
- 在类外定义一个全局listnode* list节点用于保存链表的头节点
- 在后续遍历时进行判断是否相等,相等则return,进行list->next和后序遍历的下一个节点的判断。以此类推。
// 左侧指针
ListNode left;
boolean isPalindrome(ListNode head) {
left = head;
return traverse(head);
}
boolean traverse(ListNode right) {
if (right == null) return true;
boolean res = traverse(right.next);
// 后序遍历代码
res = res && (right.val == left.val);
left = left.next;
return res;
}
链表的先序和后续遍历:
void traverse(ListNode head) {
// 前序遍历代码
traverse(head.next);
// 后序遍历代码
}
/* 倒序打印单链表中的元素值 */
void traverse(ListNode head) {
if (head == null) return;
traverse(head.next);
// 后序遍历代码
print(head.val);
}
总结
首先,寻找回文串是从中间向两端扩展,判断回文串是从两端向中间收缩。对于单链表,无法直接倒序遍历,可以造一条新的反转链表,可以利用链表的后序遍历,也可以用栈结构倒序处理单链表。
具体到回文链表的判断问题,由于回文的特殊性,可以不完全反转链表,而是仅仅反转部分链表,将空间复杂度降到 O(1)。
启发
做题的时候不要总想一步完成目的,需要将题目进行分解,将总的任务分解为多个小任务,然后找到合适的方法解决每一个小任务,最后将每个小任务的解决方法进行结合,完成目的。
解答
/**
* 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:
ListNode* reverseN(ListNode* head)
{
ListNode* pre, *cur, *t;
pre = nullptr;
cur = head;
while(cur!=nullptr)
{
t = cur->next ;
cur->next = pre;
pre = cur;
cur = t;
}
return pre;
}
bool isPalindrome(ListNode* head) {
ListNode* low, * fast;
low = fast = head;
while(fast!=nullptr&&fast->next!=nullptr)
{
low = low->next;
fast = fast->next->next;
}
if(fast!=nullptr)
{
low = low->next;
}
ListNode* list = reverseN(low);
while(list!=nullptr)
{
if(list->val!=head->val)
{
return false;
}
head = head->next;
list = list->next;
}
return true;
}
};