在一些采访中我被问到了这个问题。
在O(1)空间和线性时间的生产环境中,我被要求编写用于在链表中找到连接的代码(其形式为Y,双臂不一定相等)。 我想出了这个解决方案(我以前见过的地方):
1. Measure lengths of both lists, let them be l1 and l2 2. Move the pointer of larger list by |(l1-l2)|. 3. Now move together both the pointers, if they point to same location, that is the junction.采访者:你的代码将如何处理?
案例1.Y格式链表在结点后最后有循环。
情况2.任何一个输入列表都是循环的,它们不会合并。
情况3.Y格式列表在结点之前有一个循环。
对于案例1,我的答案是:
我将使用两个指针(一个快速和慢速)找到列表中的循环,测量两个指针所遇到的节点的长度然后继续前一个案例。然而,对于情况2和3,我能够找出没有比检测到循环时优雅退出更好的解决方案(使用双指针技术)。
我相信这个问题有更好的答案。请放下你的:)。
谢谢,
答案 0 :(得分:4)
采访者(看似)的解释使问题变得困难,以下形状也被视为有效:
A\ _____ A\ ___
\/ \ \ / \
\ / \ \ /
+---' +-------------'
/ P / P
/ /
B/ B/
即。有一个交汇点,然后列表循环回到交界处之前或之后的地方。计算列表长度的过程没有直接帮助,因为没有定义循环列表的长度。
首先请注意,循环列表末尾的循环长度可以通过此O(1)内存/ O(n)时间过程计算:
int loop_length(List *n) {
Node *hare = n, *tortoise = n;
int phase = 0, cnt = 0;
while (true) {
hare=hare->next; hare=hare->next; tortoise=tortoise->next;
if (hare==tortoise) phase++;
if (phase==1) cnt++;
if (phase==2) return cnt;
}
}
例如,考虑循环列表
(1)-->(2)-->(3)-->(4)
| |
(6)<--(5)
该算法的工作原理如下(T =龟,H =野兔):
/--------\
1--2--3--4--5--6 phase cnt
HT 0 0
T H 0 0
T H 0 0
HT 1 1
T H 1 2
H T 1 3
T H 1 4
HT 2 4 : TERMINATED, cnt=4
现在,如果在形成循环结点的节点之前有X个节点(在示例节点(3)中),即X = 2,并且循环由C个节点组成(在示例中C = 4)当乌龟在X步后第一次进入连接点时,兔子处于位置(2X-X)%C的循环中,即(X%C)(在该例子中,乌龟在2步后进入(3)然后第3只野兔位于L =(2%4 = 2)位置,即在节点(5)中(指数从零开始)。现在将采取(CL-1)步骤使野兔到达乌龟(1因为野兔具有L步的“优势”,这意味着算法直到野兔第一次遇到乌龟的步数
X + (C - X % C - 1) ; in the example 2 + (4 - 2 - 1) = 3
C是已知的(由算法计算),并且可以计算总步数(由S表示),即我们有
S + 1 - C = X - X % C
现在假设野兔作为Q步骤的额外优势,即野兔在算法开始之前先取下一个Q下一个指针;然后当乌龟进入交界点时,野兔就在位置((X + Q)%C),我们得到了
S + 1 - C = X - (X + Q) % C
现在给出计算从“A”和“B”到公共连接点P的路径长度差异的过程(表示长度a和b以及它们的差异因此ab)(假设a> b,不失一般性)。
首先从起点A运行算法,计算周期长度C并存储步骤数S_A。然后运行它以便乌龟从A开始并且野兔在B 并计算步数S_X。这意味着兔子现在具有(a-b)节点的优点,即
S_X + 1 - C = a - (a + (a - b)) % C = a - (2a - b) % C
因此
S - S_X == (a - b) modulo C
即。差值给出模C的长度差;通过C计算长度差的商通常从起点B运行算法,得到步数S_B,即全部一起
S_A + 1 - C = a - a % C
S_B + 1 - C = b - b % C
S_X - S_A == (a - b) % C
减去前两个方程式得到
S_A - S_B = (a - b) + [-1 * (a % C) + b % C]
方括号中的术语是] -C,+ C [,所以
(S_A - S_B) - C < (a - b) < (S_A - S_B) + C
在这个区间中,最多有两个相等的差(S-S_X)模C;用它们来试图发现连接点---问题解决了。
示例:
A(1)--(2)
|
B(3)--(4)--(5)--(6)
\_________/
在S_A的计算中,野兔和乌龟在(5)处的3个步骤之后相遇并且返回循环长度3。在S_B的计算中,野兔和乌龟在(6)处的3个步骤之后相遇并且返回循环长度3。对于S_X,野兔进入B和龟在A;他们在(4)的两个步骤后见面。这给了
0 - 3 < (a - b) < 0 + 3
(3 - 2) == (a - b) modulo 3
即。 (a-b)之间的长度差为1模3;这给出了可能的长度差异{-2,+ 1};假设a>&gt;忽略-2。 b,所以我们得到a = b + 1.然后通过从A向前遍历到(2)的第一个+1节点找到连接点,然后以相同的速度从两个臂前进直到找到连接点。
与非共享循环和/或没有循环的情况集成,作为练习给读者。