382. 链表随机节点Normal水塘抽样算法

Posted pre_eminent

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了382. 链表随机节点Normal水塘抽样算法相关的知识,希望对你有一定的参考价值。

题目:

给你一个单链表,随机选择链表的一个节点,并返回相应的节点值。

每个节点 被选中的概率一样 。


实现 Solution 类:

Solution(ListNode head) 使用整数数组初始化对象。
int getRandom() 从链表中随机选择一个节点并返回该节点的值。

链表中所有节点被选中的概率相等。
 


示例:

输入
["Solution", "getRandom", "getRandom", "getRandom", "getRandom", "getRandom"]
[[[1, 2, 3]], [], [], [], [], []]
输出
[null, 1, 3, 2, 2, 3]


解释
Solution solution = new Solution([1, 2, 3]);
solution.getRandom(); // 返回 1
solution.getRandom(); // 返回 3
solution.getRandom(); // 返回 2
solution.getRandom(); // 返回 2
solution.getRandom(); // 返回 3
// getRandom() 方法应随机返回 1、2、3中的一个,每个元素被返回的概率相等。
 


提示:

链表中的节点数在范围 [1, 10^4] 内
-10^4 <= Node.val <= 10^4
至多调用 getRandom 方法 10^4 次

进阶:

如果链表非常大且长度未知,该怎么处理?
你能否在不使用额外空间的情况下解决此问题?


思路:

一轮遍历

生成随机数,

如果概率是1/i就替换


解答:

/**
 * Definition for singly-linked list.
 * function ListNode(val, next) 
 *     this.val = (val===undefined ? 0 : val)
 *     this.next = (next===undefined ? null : next)
 * 
 */
/**
 * @param ListNode head
 */
var Solution = function(head) 
    // 构造函数保留头节点
    this.head = head;
;

/**
 * @return number
 */
Solution.prototype.getRandom = function() 
    let i = 1;
    let res = 0;
    for(let node = this.head;node !== null;node = node.next)
        // 如果是1/i的概率,就替换结果
        // [0, 1)
        let r = Math.random(1);
        let p = Math.floor(r * i);
        if(p === 0)
            res = node.val;
        
        i++;
    
    return res;
;

/**
 * Your Solution object will be instantiated and called as such:
 * var obj = new Solution(head)
 * var param_1 = obj.getRandom()
 */

以上是关于382. 链表随机节点Normal水塘抽样算法的主要内容,如果未能解决你的问题,请参考以下文章

LeetCode Algorithm 382. 链表随机节点

LeetCode Algorithm 382. 链表随机节点

398. 随机数索引Normal水塘抽样算法

水塘抽样算法

LeetCode 1716. 计算力扣银行的钱 / 382. 链表随机节点(蓄水池抽样) / 1220. 统计元音字母序列的数目(动规,矩阵快速幂)

水塘抽样算法与等概率证明