Algorithm 在链接列表中查找回文

Algorithm 在链接列表中查找回文,algorithm,linked-list,palindrome,Algorithm,Linked List,Palindrome,这是一个面试问题 给定一个单连通的链表,找到最大的回文 在名单上。(您可以假设回文的长度为偶数) 我采用的第一种方法是使用堆栈——我们从一开始就遍历列表,并不断输入字母。每当我们发现堆栈顶部的字母与链表上的下一个字母相同时,就开始弹出(并增加链表指针),并设置匹配字母数的计数。在我们发现不匹配后,将从堆栈中弹出的所有字母推回,然后继续推送和弹出操作。这种方法的最坏情况复杂度是O(n2),例如,当链表只是由相同字母组成的字符串时 为了提高空间和时间复杂度(通过一些常数因子),我建议将链表复制到一个

这是一个面试问题

给定一个单连通的链表,找到最大的回文
在名单上。(您可以假设回文的长度为偶数)


我采用的第一种方法是使用堆栈——我们从一开始就遍历列表,并不断输入字母。每当我们发现堆栈顶部的字母与链表上的下一个字母相同时,就开始弹出(并增加链表指针),并设置匹配字母数的计数。在我们发现不匹配后,将从堆栈中弹出的所有字母推回,然后继续推送和弹出操作。这种方法的最坏情况复杂度是O(n2),例如,当链表只是由相同字母组成的字符串时

为了提高空间和时间复杂度(通过一些常数因子),我建议将链表复制到一个数组中,并在数组中找到大小最大的回文,该回文同样需要O(n2)时间复杂度和O(n)空间复杂度

有没有更好的方法来帮助我(

这里有一个O(n^2)算法:

  • 将列表转换为双链接列表

  • 要有一个等长的回文,你需要有两个相邻的相同字母。 因此,迭代每对相邻字母(其中n-1个),在每次迭代中,如果字母相同,找到中间字母为这两个的最大回文


  • 如果你将列表复制到一个数组中,下面可能是有用的:因为我们只考虑长度回文,所以我假设这种情况,但是该技术可以很容易地扩展到奇数回文的工作。

    我们存储的不是回文的实际长度,而是长度的一半,因此我们知道可以向左/向右移动多少个字符

    考虑这个词:
    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
    • f←o←B←A.←r r→A.→b
      yay:)
    • 等等

    如果需要再次恢复列表,请在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;
    }