leetcode382. Linked List Random Node

这道题本质是到蓄水池算法


image.png

https://leetcode.com/problems/linked-list-random-node/discuss/85659/brief-explanation-for-reservoir-sampling
https://zhuanlan.zhihu.com/p/29178293

先说一下普遍的情况吧:
要求对于一个流式数据,在不知道n的情况下,保证能够随机取出k个数。

只要我们保证对于每一个新的数,都以k/(k+i)的概率取值,直到k+i = n为止即可。

对于k = 1的情况:设一个额外的桶长度为1

取第一个数的概率为1;

取第二个数的概率为1/2,那么对于第一个数,依然留在桶里的概率为1 * 1/2(不取第二个数);

取第三个数的概率为1/3,那么对于第一个数,依然留在桶里的概率为1 * 1/2 * (1 – 1/3)=1/3(原先的概率乘以不取第三个数的概率),对于第二个数,依然留在桶里的概率为1/2 * (1 – 1/3)=1/3(同理);

取第四个数的概率为1/4,那么对于第一个数,1 * 1/2 * (1 – 1/3) * (1 – 1/4) = 1/4。第二个数,1/2 * (1 – 1/3) * (1 – 1/4) = 1/4。第三个数,1/3 * (1 – 1/4) = 1/4

以此类推,直到n,n中每个数取到的概率都是1/n。

对于k>1的情况:设桶长度为k

取前k个数的概率都是1;

取第k+1个数概率为k/(k + 1),对于第一个数,1/(k+1) (没有选中第k+1个数,1 - (k/k+1)) + k/(k + 1) * (k - 1)/k (选中了第k+1个数,但是替换的是其他的k-1个数,而非第一个数)。对于剩下的k-1个数同理;

取第k+2个数概率为k/(k + 2),同上;

以此类推,直到n,n中每个数取到的概率都是k/n。

再看下本题的内容,要求以等概率的形式取得链表中的每个节点的值,所以我们只要保证,随着链表往后遍历,每次都是以1/i的概率取得当前节点的值就可以了

class Solution {
    ListNode p;
    /** @param head The linked list's head.
        Note that the head is guaranteed to be not null, so it contains at least one node. */
    public Solution(ListNode head) {
        this.p = head;
    }
    
    /** Returns a random node's value. */
    public int getRandom() {
        Random random = new Random();
        ListNode cur = p;
        int res = cur.val;
        for (int i = 1; cur.next != null; i++) {
            cur = cur.next;
            if (random.nextInt(i + 1) == i) res = cur.val;
        }
        return res;
    }
}

你可能感兴趣的:(leetcode382. Linked List Random Node)