在Y公司的笔试题中遇见了这样一个题目:
一个单链表,如何使用O(1)的空间复杂度判定其是否为对称链表,例如A->B->C->T->C->B->A就是一个对称链表。
首先最自然的就能想到N^2的算法:
查找1号和最后一个是否相同,再查找2号和倒数第二个。。。查找i和N-i是否相同。
但是这个算法明显不是最优解答。
对链表的分析之后可以看出,如果找到中间节点,从中间节点断开链表,反向链表后部的部分,再一起遍历两个链表,这样的算法的时间复杂度一定是N,而反向链表所需要的空间开销也为常数。
代码如下:
#include <iostream>
using namespace std;
struct Node{
int data;
Node *next;
};
Node *head;
int initial()
{
head = new Node;
head->data = 0;
head->next = NULL;
Node *pNode = head;
for (int i=1;i<6;++i)
{
pNode->next = new Node;
pNode = pNode->next;
pNode->data = i;
pNode->next = NULL;
}
for (int i=5;i>=0;--i)
{
pNode->next = new Node;
pNode = pNode->next;
pNode->data = i;
pNode->next = NULL;
}
return 0;
}
void deleteList()
{
Node *pNode = head;
while(pNode){
Node *q = pNode->next;
delete pNode;
pNode = q;
}
}
void printList(Node *head)
{
Node *pNode = head;
while(pNode){
cout<<pNode->data<<endl;
pNode = pNode->next;
}
}
Node* reverseList(Node *head)
{
Node *pNode = head->next,
*pNext = NULL;
head->next = NULL;
while (pNode)
{
pNext = pNode->next;
pNode->next = head;
head = pNode;
pNode = pNext;
}
return head;
}
bool yahooList()
{
int len = 0;
Node *pNode = head;
//get length
while (pNode)
{
++len;
pNode = pNode->next;
}
if (1 == len)
{
return true;
}
//找中点,如果是奇数个则指向中点的下一个元素
bool bOdd = len & 0x00000001;//odd num delete middle number
int mid = len>>1;
int i = 0;
pNode = head;
while(i++ != mid)
pNode = pNode->next;
if (bOdd)
pNode = pNode->next;
Node *pOther = reverseList(pNode);
#ifdef _DEBUG
cout<<"the reverse list is:"<<endl;
printList(pOther);
#endif // _DEBUG
//顺序比较
pNode = head;
while (pOther && pNode)
{
if (pOther->data != pNode->data)
{
return false;
}
pOther = pOther->next;
pNode = pNode->next;
}
return true;
}
int main()
{
initial();
printList(head);
cout<<yahooList()<<endl;
return 0;
}