将链接列表拆分为3个链接列表

时间:2011-04-17 05:33:25

标签: algorithm data-structures linked-list

问题是写一个算法将给定的链表有效地分成三个几乎等价的链表,即

if we have a linkedlist {1->5->7->9->2->4->6} the output should be   
LL_1={1->5->7}, LL_2={9->2}, LL_3={4->6}

我的解决方案执行以下操作:

1-iterate the given linkedlist from start to end
2-at each node cache the nodes reference into an array, say ll_array
3-now we have the linkedlists size (ll_array.lenght) and all the node references 
  in an array which we can use to create the three linkedlists in a 
  straightforward manner

但上述算法需要O(n)时间和O(n)空间。这可以做得更好吗?

解决方案: 基于ChrisH的hints。这种替代方案需要O(n)时间,但需要恒定的额外空间(对于临时持有者)

    
Node {
    String value;
    Node next;
}
split(Node rootNode /*root node of input linked-list*/) {
    // root node of the three resulting linked-lists
    Node root_1 = rootNode;
    Node root_2 = null;
    Node root_3 = null;

    // previous nodes of linked-lists 2 & 3 (since ours is a singly-linked-list)
    Node prev_2 = null;
    Node prev_3 = null;

    int count = 0; // counter
    Node currentNode = rootNode; // temp holder

    while(currentNode != null) {
        count++;

        if (count > 3) {
            int mod = count % 3;
            if (mod == 1) {
                prev_2 = root_2;
                root_2 = root_2.next;

                prev_3 = root_3;
                root_3 = root_3.next;
            } else if (mod == 2) {
                prev_3 = root_3;
                root_3 = root_3.next;
            }
        } else if (count == 2) { // initialize linked-list-2
            root_2 = currentNode;
        } else if (count == 3) { // initialize linked-list-3
            root_3 = currentNode;
        }

        currentNode = currentNode.next;
    }

    // unlink linked-lists 2 & 3 from the chain 
    prev_2.next = null; 
    prev_3.next = null;

}

4 个答案:

答案 0 :(得分:4)

这听起来像是家庭作业,所以我要提供一个提示而不是一个完整的答案。

您将找不到在少于O(n)时间内运行的算法,因为将某些内容拆分为相同大小的部分需要知道整体的大小,并且查找链接列表的长度需要O(n)。

但是你可以用O(1)额外的空间来解决这个问题。解决方案的关键是您只需要在列表中找到需要剪切的点。这些点应该由大致相等数量的节点分开。

知道列表的长度需要迭代器来访问每个节点。需要知道长度的1/3以及知道长度的2/3需要什么?如果你按照这些思路思考,我认为答案就会出现。

答案 1 :(得分:2)

这会有用吗?

int split_list(struct node *ll)
{
    struct node *l1, *l2, *l3;
    if(!(ll && ll->next && ll->next->next)){
        printf("Need atleast 3 elements\n");
        return -1;
    }
    l1 = ll;
    l2 = ll->next;
    l3 = ll->next->next;
    while(l3 && l3->next && l3->next->next){
        l1 = l1->next;
        l2 = l2->next->next;
        l3 = l3->next->next->next;
    }
    l3 = l2->next;
    l2->next = NULL;
    l2 = l1->next;  
    l1->next = NULL;
    l1 = ll;
    printf("l1:%d, l2=%d, l3=%d\n", l1->data, l2->data, l3->data);

    return 0;
}

答案 2 :(得分:1)

解决方案类似于从单个链接列表中的末尾查找第n个元素。而不是在那里使用两个指针,我们需要使用三个不同速度的指针来解决这个问题(代码已在上面给出)

答案 3 :(得分:0)

您不能在少于O(N)时间内执行任何进入链接列表中间的操作,因为如果不遍历其中一个端点的每个节点,就无法进入列表中间。< / p>

如果你的列表是不可变的,你在空间中也不能比O(N)做得更好,因为你可以重用的唯一一点是最后三分之一。如果您可以修改列表以将其拆分为三分之一,则可以通过重用所有节点并在前两个链中消除tailnext指针来在O(1)空间中执行此操作。 / p>