判断一个链表是否是回文结构
判断一个链表是否是回文结构
【题目】给定一个单链表的头结点,请判断该链表是否为回文结构
【要求】如果链表长度为N,时间复杂度要求为O(N),额外空间复杂度为O(1)
【示例】1->2->2->1 true ;1->2->1 true ;1->2->3 false
【解题思路】
- 栈
- 把链表的全部内容依次放入栈中,再依次弹出栈中元素,并与链表依次进行比较,如果都相等,那么为回文结构,否则不是
- 时间复杂度:O(N)
- 空间复杂度:O(N)
- 快慢指针 + 栈
- 快指针一次走两步,慢指针一次走一步,当快指针走到结尾时,慢指针走到一半,然后把慢指针后面的部分,放到栈中
- 时间复杂度:O(N)
- 空间复杂度:O(N/2)
- 有限个指针
- 改变链表右侧区域,使整个右半区域反转,最后指向中间结点;利用指针分别从两端移动,每移动一次比较两值是否一样。最后把链表恢复成原来的样子
- 空间复杂度O(1)
栈实现
bool isPalindrome1(Node* head){
Node *p = head->next;
stack<int> sta;
while(p){//第一个循环用来把链表数据存入栈中
sta.push(p->data);
p = p->next;
}
p = head->next;
while(p){//第二个循环时为了对比链表数据与栈弹出的数据
if(p->data != sta.top())
return false;
sta.pop();
p = p->next;
}
return true;
}
栈+快慢指针
空间复杂度:O(N/2)
bool isPalindrome2(Node* head){
if(head == NULL || head->next == NULL)
return true;
Node* right = head->next;
Node* cur = head;
while(cur->next != NULL && cur->next->next != NULL){
//cout << "right->data:" << right->data << endl;
//cout << "cur->data:" << cur->data << endl;
right = right->next;
cur = cur->next->next;
}
stack<Node*> sta;
while(right != NULL){//把中点以后的部分放入栈中
sta.push(right);
//cout << "放入栈中的数据为:" << right->data << endl;
//cout << sta.top()->data << endl;
right = right->next;
}
while(!sta.empty()){
//cout << sta.top()->data << endl;
if(head->next->data != sta.top()->data){
return false;
}
head = head->next;
sta.pop();
}
return true;
}
有限个变量
bool isPalindrome3(Node* head){
if(head == NULL || head->next == NULL)
return true;
Node* n1 = head;
Node* n2 = head;
//find the mid
while(n2->next != NULL && n2->next->next != NULL){//查找中间结点
cout << "n1->data : " << n1->data << endl;
cout << "n2->data : " << n2->data << endl;
n1 = n1->next;//n1指向中部
n2 = n2->next->next;//n2指向尾部
}
n2 = n1->next;//n2 right part first node
n1->next = NULL;
Node* n3 = NULL;
while(n2 != NULL){//右半区反转
n3 = n2->next;//n3 save next node
n2->next = n1;//下一个反转结点
n1 = n2;//n1 move
n2 = n3;//n2 move
}
n3 = n1;//n3 save the last node
n2 = head->next;//left first node
bool res = true;
while(n1 != NULL && n2 != NULL){
if(n1->data != n2->data){
res = false;
break;
}
n1 = n1->next;//left to mid
n2 = n2->next;//right to mid
}
n1 = n3->next;
n3->next = NULL;
while(n1 != NULL){//恢复列表
n2 = n1->next;
n1->next = n3;
n3 = n1;
n1 = n2;
}
return res;
}
【参考】程序员代码面试指南——左程云