zoukankan      html  css  js  c++  java
  • 两种判圈法——floyd和brent

    这个东西其实挺naive的。

    floyd判圈

    大概就是快指针和慢指针以(1 : 2)的速度前进。
    当快指针再次与慢指针相遇时,它们行进路程的差值一定为圈长的整数倍。
    为什么?
    考虑一般情况就是走了一条链后进了一个圈。
    设链长为(m),圈长为(n),慢指针走了(a)圈,快指针走了(b)圈,它们相遇在下一圈的距离入圈点(d)的位置,则

    [s = m + n * a + d \ 2s = m + n * b + d \ ]

    (dif = s = n * (a - b)),有(n | dif)
    考虑模拟上述过程,在两个指针再次相遇时停下来。
    此时将慢指针移动至初始结点,快指针不动,以(1 : 1)的速度继续前进。
    由于(m + d = n (b - 2a))(n | (m + d)),思考一下,发现快慢指针一定能在入圈点相遇(此时慢指针走了(m),快指针距离入圈点(d + m),在模(n)意义下恰好为(0))。
    模拟整个过程就可以通过(mathcal O(m + n))的时间得出答案。

    int *h = head, *t = head;
    do {
    	h = h->next;
    	if (h != null) {
    		h = h->next;
    	}
    	t = t->next;
    } while (h != t || h != null);
    if (h != null) {
    	t = head;
    	while (h != t) {
    		h = h->next;
    		t = t->next;
    	}
    	p = h;
    }
    

    brent判圈

    开始令快慢指针指向起始节点,让慢指针保持不动,快指针走(2 ^ i)步。在快指针走每一步后,判断快慢指针是否相遇。如果走了(2 ^ i)步后没有相遇,则将慢指针的位置移到快指针处,并且(i++);否则找到了圈,退出即可。复杂度同floyd(常数更小)。

    int *t = head, *h = head;
    int s = 0, lim = 2;
    while (1) {
    	if (h == null) {
    		// no loop
    		break;
    	}
    	++s;
    	if (h == t) {
    		// find loop: len = s
    		break;
    	}
    	if (s == lim) {
    		s = 0;
    		lim <<= 1;
    		t = h;
    	}
    }
    
  • 相关阅读:
    423. Reconstruct Original Digits from English
    400. Nth Digit
    397. Integer Replacement
    396. Rotate Function
    365. Water and Jug Problem
    335. Self Crossing
    319. Bulb Switcher
    线段树-hdu2795 Billboard(贴海报)
    线段树---求逆序数
    线段树——单点替换区间最值
  • 原文地址:https://www.cnblogs.com/psimonw/p/11697526.html
Copyright © 2011-2022 走看看