原题链接:https://leetcode.com/problems/swap-nodes-in-pairs/
我在github上的leetcode仓库是:https://github.com/cooljacket/leetcodes
问题
用O(n)的时间和O(1)的空间,判断一个单链表是否是回文的。
思路
先把前一半的链表反转,从中间开始往两边走,边走边判断
缺点
改变了链表的结构
solution
判断过后把结构恢复。
代码
首先贴一下简单的做法,不恢复链表的结构的:
class Solution {
public:
// 思路:先把前一半的链表反转,从中间开始往两边走,边走边判断
// 缺点:改变了链表的结构
// solution:在判断的时候顺手把结构恢复
bool isPalindrome(ListNode* head) {
int len = getListLength(head);
int halfSize = len >> 1, step = 0;
ListNode *last = NULL;
ListNode* rightHead = reverseList(head, last, halfSize);
ListNode *leftHead = last;
if (len % 2 != 0)
rightHead = rightHead->next;
while (leftHead != NULL) {
if (leftHead->val != rightHead->val)
return false;
leftHead = leftHead->next;
rightHead = rightHead->next;
}
return true;
}
// 遍历链表,计算其长度
int getListLength(ListNode* head) {
int len = 0;
while (head != NULL) {
++len;
head = head->next;
}
return len;
}
// 反转一段链表times步
ListNode* reverseList(ListNode* head, ListNode*& last, int times) {
ListNode *now = head, *tmp;
int step = 0;
while (step++ < times && now != NULL) {
tmp = now->next;
now->next = last;
last = now;
now = tmp;
}
return now;
}
};
其实恢复就是对反转的那段链表,再反转一遍就好了!比如这样:
class Solution {
public:
// 思路:先把前一半的链表反转,从中间开始往两边走,边走边判断
// 缺点:改变了链表的结构
// solution:在判断的时候顺手把结构恢复
bool isPalindrome(ListNode* head) {
int len = getListLength(head);
int halfSize = len >> 1, step = 0;
ListNode *last = NULL;
ListNode* rightHead = reverseList(head, last, halfSize);
ListNode *leftHead = last;
ListNode *leftHeadCopy = leftHead, *rightHeadCopy = rightHead;
if (len % 2 != 0)
rightHead = rightHead->next;
bool ans = true;
while (leftHead != NULL) {
if (leftHead->val != rightHead->val) {
ans = false;
break;
}
leftHead = leftHead->next;
rightHead = rightHead->next;
}
// 最后,恢复链表的结构
reverseList(leftHeadCopy, rightHeadCopy, halfSize);
return ans;
}
// 遍历链表,计算其长度
int getListLength(ListNode* head) {
int len = 0;
while (head != NULL) {
++len;
head = head->next;
}
return len;
}
// 反转一段链表times步
ListNode* reverseList(ListNode* head, ListNode*& last, int times) {
ListNode *now = head, *tmp;
int step = 0;
while (step++ < times && now != NULL) {
tmp = now->next;
now->next = last;
last = now;
now = tmp;
}
return now;
}
};
更多
其实一些小地方的运算,比如求长度的一般,可以直接除以2,但是用移位会更快!还有判断奇偶性,用模运算也是浪费,直接(x & 1) > 0,true就是奇数,false就是偶数。
这些操作在编译原理里边叫做”运算强度削弱“,如果追求效率的话,可以自己就这样做了,因为编译器不一定会帮你做好。同时注意注释,不然不懂的人可能看不太懂。