Algorithm 在链接列表中查找回文
这是一个面试问题 给定一个单连通的链表,找到最大的回文Algorithm 在链接列表中查找回文,algorithm,linked-list,palindrome,Algorithm,Linked List,Palindrome,这是一个面试问题 给定一个单连通的链表,找到最大的回文 在名单上。(您可以假设回文的长度为偶数) 我采用的第一种方法是使用堆栈——我们从一开始就遍历列表,并不断输入字母。每当我们发现堆栈顶部的字母与链表上的下一个字母相同时,就开始弹出(并增加链表指针),并设置匹配字母数的计数。在我们发现不匹配后,将从堆栈中弹出的所有字母推回,然后继续推送和弹出操作。这种方法的最坏情况复杂度是O(n2),例如,当链表只是由相同字母组成的字符串时 为了提高空间和时间复杂度(通过一些常数因子),我建议将链表复制到一个
在名单上。(您可以假设回文的长度为偶数)
我采用的第一种方法是使用堆栈——我们从一开始就遍历列表,并不断输入字母。每当我们发现堆栈顶部的字母与链表上的下一个字母相同时,就开始弹出(并增加链表指针),并设置匹配字母数的计数。在我们发现不匹配后,将从堆栈中弹出的所有字母推回,然后继续推送和弹出操作。这种方法的最坏情况复杂度是O(n2),例如,当链表只是由相同字母组成的字符串时 为了提高空间和时间复杂度(通过一些常数因子),我建议将链表复制到一个数组中,并在数组中找到大小最大的回文,该回文同样需要O(n2)时间复杂度和O(n)空间复杂度 有没有更好的方法来帮助我(这里有一个O(n^2)算法:
如果你将列表复制到一个数组中,下面可能是有用的:因为我们只考虑长度回文,所以我假设这种情况,但是该技术可以很容易地扩展到奇数回文的工作。
我们存储的不是回文的实际长度,而是长度的一半,因此我们知道可以向左/向右移动多少个字符 考虑这个词:aabbababab
。我们正在寻找最长的回文
a a b b a b b a b a b (spaces for readability)
°^° start at this position and look to the left/right as long as possible,
1 we find a palindrome of length 2 (but we store "1")
we now have a mismatch so we move the pointer one step further
a a b b a b b a b a b
^ we see that there's no palindrome at this position,
1 0 so we store "0", and move the pointer
a a b b a b b a b a b
° °^° ° we have a palindrome of length 4,
1 0 2 so we store "2"
naively, we would move the pointer one step to the right,
but we know that the two letters before pointer were *no*
palindrome. This means, the two letters after pointer are
*no* palindrome as well. Thus, we can skip this position
a a b b a b b a b a b
^ we skipped a position, since we know that there is no palindrome
1 0 2 0 0 we find no palindrome at this position, so we set "0" and move on
a a b b a b b a b a b
° ° °^° ° ° finding a palindrome of length 6,
1 0 2 0 0 3 0 0 we store "3" and "mirror" the palindrome-length-table
a a b b a b b a b a b
^ due to the fact that the previous two positions hold "0",
1 0 2 0 0 3 0 0 0 we can skip 2 pointer-positions and update the table
a a b b a b b a b a b
^ now, we are done
1 0 2 0 0 3 0 0 0 0
这意味着:一旦我们找到回文位置,我们就可以推断出表格的某些部分
另一个例子:aaaaaa b
a a a a a a b
°^°
1
a a a a a a b
° °^° °
1 2 1 we can fill in the new "1" since we found a palindrome, thus mirroring the
palindrome-length-table
a a A A a a b (capitals are just for emphasis)
^ at this point, we already know that there *must* be a palindrome of length
1 2 1 at least 1, so we don't compare the two marked A's!, but start at the two
lower-case a's
我的观点是:一旦我们找到回文,我们就可以镜像(至少部分)回文长度表,从而推断新字符的信息。
通过这种方式,我们可以保存比较。我们可以提出一种空间复杂度为O(1)的O(n²)算法,如下所示:
考虑f→o→B→A.→R→R→A.→b
:
在访问时反向浏览列表。从x=f
和y=f开始。下一步
:
- 设置
x.next=null
- 福→B→A.→R→R→A.→B ^ ^ | \ xy 并检查两个列表(x和y)的链接数量是否相等
- 现在继续。(
,tmp=y.next
,y.next=x
,x=y
) 例如,在第二步中,它将产生y=tmp
,使用f←o b→A.→R→R→A.→b
和x=o
,现在再次检查它是否为回文并继续:y=b
f←o←b a→R→R→A.→b
f←o←B←a r→R→A.→b
yay:)f←o←B←A.←r r→A.→b
- 等等
如果需要再次恢复列表,请在O(n)中再次将其反转。这是一个经过充分分析的问题,时间复杂度O(n)
- 您可以反转原始字符串(例如
和str
)str\u reversed
str
和str\u反转中查找
- 正在构建一个后缀树(O(N)),具有固定时间的最低公共祖先检索
首先找到链表的中点,以便遍历链表并计算节点数
假设节点数为N,中点为N/2
现在遍历到中点节点,并开始反转链表直到结束,这可以在O(n)复杂度的地方完成
然后比较从起点到中点的元素和从中点到终点的元素,如果它们都相等,字符串是回文,否则断开
时间复杂度:-O(n)
空间复杂度:-O(1)我是通过在O(n)时间内使用递归来实现的。
我是通过
假设我们有一个源链接列表,现在复制整个链接列表
列表到其他链接列表,即目标链接列表李>
现在反转目标链表李>
现在检查源链表和目标链表中的数据是否相等,如果相等则为回文,
否则它们就不是回文
现在释放目标链接列表
代码:
#包括
#包括
结构节点{
int数据;
结构节点*链接;
};
int-append\u源(结构节点**源,int-num){
结构节点*temp,*r;
温度=*源;
if(temp==NULL){
temp=(结构节点*)malloc(sizeof(结构节点));
温度->数据=num;
temp->link=NULL;
*源=温度;
返回0;
}
while(临时->链接!=NULL)
温度=温度->链接;
r=(结构节点*)malloc(sizeof(结构节点));
r->data=num;
温度->链接=r;
r->link=NULL;
返回0;
}
int显示(结构节点*源){
结构节点*temp=源;
while(temp!=NULL){
printf(“列表数据=%d\n”,临时->数据);
温度=温度->链接;
}
返回0;
}
int copy_列表(结构节点**源,结构节点**目标){
结构节点*sou=*source,*temp=*target,*r;
while(sou!=NULL){
if(temp==NULL){
temp=(结构节点*)malloc(sizeof(结构节点));
临时->数据=sou->数据;
temp->link=NULL;
*目标=温度;
}
否则{
while(临时->链接!=NULL)
温度=温度->链接;
r=(结构节点*)malloc(sizeof(结构节点));
r->data=sou->data;
温度->链接=r;
r->link=NULL;
f o→b→a→r→r→a→b
^ ^
| \
x y
#include<stdio.h>
#include<malloc.h>
struct node {
int data;
struct node *link;
};
int append_source(struct node **source,int num) {
struct node *temp,*r;
temp = *source;
if(temp == NULL) {
temp = (struct node *) malloc(sizeof(struct node));
temp->data = num;
temp->link = NULL;
*source = temp;
return 0;
}
while(temp->link != NULL)
temp = temp->link;
r = (struct node *) malloc(sizeof(struct node));
r->data = num;
temp->link = r;
r->link = NULL;
return 0;
}
int display(struct node *source) {
struct node *temp = source;
while(temp != NULL) {
printf("list data = %d\n",temp->data);
temp = temp->link;
}
return 0;
}
int copy_list(struct node **source, struct node **target) {
struct node *sou = *source,*temp = *target,*r;
while(sou != NULL) {
if(temp == NULL) {
temp = (struct node *) malloc(sizeof(struct node));
temp->data = sou->data;
temp->link = NULL;
*target = temp;
}
else {
while(temp->link != NULL)
temp = temp->link;
r = (struct node *) malloc(sizeof(struct node));
r->data = sou->data;
temp->link = r;
r->link = NULL;
}
sou = sou->link;
}
return 0;
}
int reverse_list(struct node **target) {
struct node *head = *target,*next,*cursor = NULL;
while(head != NULL) {
next = head->link;
head->link = cursor;
cursor = head;
head = next;
}
(*target) = cursor;
return 0;
}
int check_pal(struct node **source, struct node **target) {
struct node *sou = *source,*tar = *target;
while( (sou) && (tar) ) {
if(sou->data != tar->data) {
printf("given linked list not a palindrome\n");
return 0;
}
sou = sou->link;
tar = tar->link;
}
printf("given string is a palindrome\n");
return 0;
}
int remove_list(struct node *target) {
struct node *temp;
while(target != NULL) {
temp = target;
target = target->link;
free(temp);
}
return 0;
}
int main()
{
struct node *source = NULL, *target = NULL;
append_source(&source,1);
append_source(&source,2);
append_source(&source,1);
display(source);
copy_list(&source, &target);
display(target);
reverse_list(&target);
printf("list reversed\n");
display(target);
check_pal(&source,&target);
remove_list(target);
return 0;
}