【问题标题】:Time Complexity?时间复杂度?
【发布时间】:2018-08-25 08:33:15
【问题描述】:

问题是找到两个排序链表的交集并将公共元素存储在第三个链表中。

我的方法是创建临时指针 temp1temp2 分别初始化为 head1(列表 1 的头部)和 head2(列表 2 的头部)。然后遍历两个列表并比较元素和相应地移动temp1temp2。代码工作正常。

测试用例: 第一个链表=> 1->2->3->4->6 第二个链表是 2->4->6->8,那么函数应该创建并返回第三个链表为 2->4->6。

但我对什么是时间复杂度感到困惑:O(m+n) 还是 O(min(m,n))? (m,n 是列表 1 和列表 2 中元素的数量)。

我的代码:

#include<stdio.h>
#include<stdlib.h>

/* Link list node */
struct Node
{
    int data;
    struct Node* next;
};
void append(struct Node** head_ref, int new_data)
{
    /* 1. allocate node */
    struct Node* new_node = (struct Node*) malloc(sizeof(struct Node));

    struct Node *last = *head_ref;  /* used in step 5*/

    /* 2. put in the data  */
    new_node->data  = new_data;

    /* 3. This new node is going to be the last node, so make next 
          of it as NULL*/
    new_node->next = NULL;

    /* 4. If the Linked List is empty, then make the new node as head */
    if (*head_ref == NULL)
    {
       *head_ref = new_node;
       return;
    }  

    /* 5. Else traverse till the last node */
    while (last->next != NULL)
        last = last->next;

    /* 6. Change the next of last node */
    last->next = new_node;
    return;    
}

struct Node* sortedIntersect(struct Node* head1,struct Node*head2)
{
    struct Node*head3=NULL;
    struct Node*temp1=head1;
    struct Node*temp2=head2;
    while(temp1!=NULL&&temp2!=NULL)
    {
        if(temp1->data<temp2->data)
        {if(temp1->next!=NULL)
            temp1=temp1->next;
            else
            break;
        } 
        else if(temp1->data>temp2->data)
        {
            if(temp2->next!=NULL)
            temp2=temp2->next;
            else{
                break;
            }
        }
        else 
        {
            append(&head3,temp1->data);
            temp1=temp1->next;
            temp2=temp2->next;
        }
    }
    return head3;
}


/* Function to insert a node at the beginging of the linked list */
void push(struct Node** head_ref, int new_data)
{
    /* allocate node */
    struct Node* new_node = (struct Node*) malloc(sizeof(struct Node));

    /* put in the data */
    new_node->data = new_data;

    /* link the old list off the new node */
    new_node->next = (*head_ref);

    /* move the head to point to the new node */
    (*head_ref) = new_node;
}

/* Function to print nodes in a given linked list */
void printList(struct Node *node)
{
    while (node != NULL)
    {
        printf("%d ", node->data);
        node = node->next;
    }
}


int main()
{
    /* Start with the empty lists */
    struct Node* a = NULL;
    struct Node* b = NULL;
    struct Node *intersect = NULL;

    /* Let us create the first sorted linked list to test the functions
    Created linked list will be 1->2->3->4->5->6 */
    push(&a, 6);
    push(&a, 5);
    push(&a, 4);
    push(&a, 3);
    push(&a, 2);
    push(&a, 1);

    /* Let us create the second sorted linked list
    Created linked list will be 2->4->6->8 */
    push(&b, 8);
    push(&b, 6);
    push(&b, 4);
    push(&b, 2);

    /* Find the intersection two linked lists */
    intersect = sortedIntersect(a, b);

    printf("\n Linked list containing common items of a & b \n ");
    printList(intersect);

    return 0;
}

【问题讨论】:

    标签: c linked-list time-complexity singly-linked-list


    【解决方案1】:

    这是O(m+n)可以解决的问题

    但是,这个解决方案不是O(m+n)。您在方法intersectSorted 中添加的每个元素都使用方法append 添加,该方法遍历整个当前输出列表。

    所以时间复杂度是O((m+n)log(min(m,n))

    【讨论】:

    • 请你解释一下你是怎么做到的?
    • 我不是 100% 确定如何推导出它,但是反复遍历一个不断增加的列表通常是 O(n log n)
    • 但是这种最坏的情况永远不会发生,对吧?(对于这种情况,时间复杂度 O(m+n+log(m+n)) 成立)好像两个列表中都有最大公共元素那么这将是链表遍历的最坏情况,另一方面,如果没有公共元素,那么while循环将是最坏情况,因此实际最坏情况可能在更严格的范围内。但我们仍然可以说所花费的时间总是会小于这个。
    • @jane 嗯,这可能是真的,但我想说最坏的情况至少是 O(m log m) 或类似的东西。该附加操作将破坏任何线性。
    • 是的,这是真的。但是你能检查一次你的时间复杂度吗,它应该是 O(m+n+(m+n)log(m+n)) 就像你之前所说的那样或那个因素对数前面的项不会依赖于m或n?
    【解决方案2】:

    如同while的每次迭代,至少有一个指针指向下一个,而while终止的条件是没有一个指针到达终点,时间复杂度为O(min(m,n))

    【讨论】:

      【解决方案3】:

      worst case 中将是O(m+n)

      example: {1,3,5,7} {2,4,6,8}
      在这种情况下,您将遍历 列表。

      average 的情况下是

      O(min(m,n) + number of times you don't increment the smaller list)
      

      example : {1,2,3,4,6} {2,4,6,8,9,10}
      在这种情况下,您终止 一旦你到达第一个行列表的末尾但在你之间的循环 增加第二个列表而不增加第一个列表。

      best 的情况下,它将是O(min(m,n))

      example: {1,2,3} {1,2,3,4,}
      在这种情况下,您将终止 到达第一个列表末尾后的循环。

      【讨论】:

        猜你喜欢
        • 2016-02-13
        • 2012-08-14
        • 1970-01-01
        • 1970-01-01
        • 2013-09-12
        • 2018-08-02
        • 2014-04-29
        • 1970-01-01
        相关资源
        最近更新 更多