水塘抽样算法在leetcode中的应用

一、水塘抽样算法

作用:对于大样本量的数据集,随机选取样本
时间复杂度:O(1),一次遍历
空间复杂度:O(1)

问题:从N个样本种随机选取k个样本,传统做法要么需要借助哈希表等工具,时间复杂度为O(n);要么需要不止一次的遍历,那么怎么优化这个过程呢?

随机选取k个:遍历样本,遍历到第i个样本的时候,随机选取1到i的数字j,若j < k,则将第i个样本放到返回结果的第j个数据中。

随机选取1个:遍历样本,遍历到第i个样本的时候,随机选取1到i的数字j,若j == 0,则将第i个样本作为返回结果。

返回概率
该算法保证每个结果的返回概率相等,以k = 1为例:
在这里插入图片描述

二、应用

1、382.链表随机节点

382.链表随机结点

给你一个单链表,随机选择链表的一个节点,并返回相应的节点值。每个节点 被选中的概率一样 。

实现 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() 方法应随机返回 123中的一个,每个元素被返回的概率相等。
 

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

    def __init__(self, head: Optional[ListNode]):
        #print(head)
        self.head = head

    def getRandom(self) -> int:
        res = 0
        i = 1
        node = self.head

        while node:
            if randrange(i) == 0:
                res = node.val
            i += 1
            node = node.next

        return res

2、398.随机数索引

398.随机数索引

给定一个可能含有重复元素的整数数组,要求随机输出给定的数字的索引。 您可以假设给定的数字一定存在于数组中。

注意:
数组大小可能非常大。 使用太多额外空间的解决方案将不会通过测试。

示例:

int[] nums = new int[] {1,2,3,3,3};
Solution solution = new Solution(nums);

// pick(3) 应该返回索引 2,3 或者 4。每个索引的返回概率应该相等。
solution.pick(3);

// pick(1) 应该返回 0。因为只有nums[0]等于1。
solution.pick(1);

class Solution:

    def __init__(self, nums: List[int]):
        self.nums = nums

    def pick(self, target: int) -> int:
        ans = 0
        count = 0
        for i, num in enumerate(self.nums):
            if num == target:
                count += 1
                if randint(0, count - 1) == 0:
                    ans = i

        return ans
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值