问题是写一个算法将给定的链表有效地分成三个几乎等价的链表,即
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; }
答案 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)做得更好,因为你可以重用的唯一一点是最后三分之一。如果您可以修改列表以将其拆分为三分之一,则可以通过重用所有节点并在前两个链中消除tail
或next
指针来在O(1)空间中执行此操作。 / p>