1. 题意
给你一个单链表的头节点 head ,请你判断该链表是否为回文链表。如果是,返回 true ;否则,返回 false 。
2. 题解
2.1 链表转数组
链表不好操作,直接把链表中的数给放进数组里面。
数组里面相向双指针就可以解决了。
cpp
/**
* 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) {
vector<int> a{};
while ( head ) {
a.push_back( head->val );
head = head->next;
}
int l = 0;
int r = static_cast<int>(a.size()) - 1;
while ( l < r) {
if ( a[l] != a[r] )
return false;
l++;
r--;
}
return true;
}
};
2.2 栈反转
可以遍历链表一遍把值放入栈中,再依次出栈就是逆序输出了。
cpp
/**
* 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) {
stack<int> st;
auto cur = head;
for ( ;cur;cur=cur->next) {
st.push(cur->val);
}
while (head) {
if (head->val != st.top())
return false;
st.pop();
head = head->next;
}
return true;
}
};
2.3 尾递归+变量标记
其实这种方法跟栈的做法本质是一样的。
只是变得更加不好理解了。。。
你让我下次写,我不一定能写出来。
cpp
/**
* 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 get_ans(ListNode *head, ListNode * &pre) {
if ( head != nullptr ) {
bool res = get_ans(head->next, pre);
if ( res == false )
return false;
if ( pre->val != head->val)
return false;
pre = pre->next;
}
return true;
}
bool isPalindrome(ListNode* head) {
ListNode *&lp = head;
return get_ans( head, lp);
}
};
2.4 反转后半部分链表比较
这种做法虽然复杂,但是很有价值。
找到链表的中间位置是leetcode-876. 链表的中间结点。
反转后半部分链表是leetcod-206. 反转链表。
可以先通过快慢指针找到后半部分链表的前驱节点,
进而再找到后半部分链表的头节点。
再比较的时候,我们可以用右半部分遍历完成作为循环条件,
因为这样不需要处理链表节点数为奇数的情况。
前后部分的链不需要断,我们只需要反转一次后半部分进行比较后。
再反转恢复回去就行了。
cpp
/**
* 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 *get_mid(ListNode *head) {
if (head == nullptr)
return nullptr;
auto slow = head;
auto fast = head->next;
while (fast && fast->next) {
slow = slow->next;
fast = fast->next->next;
}
return slow;
}
ListNode *reverse_list(ListNode *head) {
ListNode *nHead{};
auto cur = head;
while ( cur ) {
auto nxt = cur->next;
cur->next = nHead;
nHead = cur;
cur = nxt;
}
return nHead;
}
// void dump_list(ListNode *head) {
// while ( head ) {
// cout << head->val << " ";
// head = head->next;
// }
// cout << "\n";
// }
bool isPalindrome(ListNode* head) {
auto pre_r = get_mid( head );
auto nHead = reverse_list( pre_r->next );
auto lp = head;
auto rp = nHead;
bool ans{ true };
while ( rp ) {
if ( lp->val != rp->val ) {
ans = false;
break;
}
lp = lp -> next;
rp = rp -> next;
}
reverse_list( nHead );
// dump_list( head );
return ans;
}
};
当然你要非要写左半部分遍历作为条件也不是不可以,
需要额外处理一些东西,包括左右部分链表的断链与恢复,
还有奇数情况的特殊处理,如何判断节点数是奇数呢?
fast
指针值为空。
cpp
/**
* 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 * reverseList(ListNode *head) {
ListNode *nHead = nullptr;
auto cur = head;
while ( cur ) {
auto nxt = cur->next;
cur->next = nHead;
nHead = cur;
cur = nxt;
}
return nHead;
}
void dump_list(const ListNode *head){
const ListNode *cur = head;
while (cur != nullptr) {
cout << cur->val << " ";
cur = cur->next;
}
cout << "\n";
}
bool isPalindrome(ListNode* head) {
if ( head == nullptr || head->next == nullptr )
return true;
auto slow = head;
auto fast = head->next;
while ( fast && fast->next ) {
slow = slow->next;
fast = fast->next->next;
}
auto lp = head;
auto nrHead = reverseList( slow->next );
auto rp = nrHead;
slow->next = nullptr;
auto lend = slow;
if ( fast != nullptr )
lend = nullptr;
bool res{true};
while ( lp != lend ) {
if ( lp->val != rp->val ) {
res = false;
break;
}
lp = lp->next;
rp = rp->next;
}
slow->next = reverseList( nrHead );
return res;
}
};