leetcode-抽样算法

528. 按权重随机选择

 

 

class Solution:

    def __init__(self, w: List[int]):
        self.pre = list(accumulate(w))
        self.total = sum(w)

    def pickIndex(self) -> int:
        x = random.randint(1, self.total)
        return bisect_left(self.pre, x)

作者:LeetCode-Solution
链接:https://leetcode.cn/problems/random-pick-with-weight/solution/an-quan-zhong-sui-ji-xuan-ze-by-leetcode-h13t/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

洗牌算法

洗牌算法,高中学的。

384 打乱数组 洗牌算法

思路:

对于一个数组来说,遍历这个数组,从当前的index到末尾[index,len(nums)-1]区间里,选一个数与当前数交换。

证明:

这样每个位置元素出现的概率都是1/n。

对于第1个位置来说,是从n个元素中随机选一个,每个元素出现的概率是1/n.

对于第2个位置来说,我们要考虑这个元素,没在之前的选择里(即没在第一个位置出现),所以,在选随机数的时候,区间为[index,len(nums)-1]。从数学公式角度来看,固定第一个位置的元素(确定这个元素没在第一个位置出现)的概率为(n-1)/n,从剩下的元素里选一个的概率是1/(n-1)。

class Solution(object):
    def __init__(self, nums):
        """
        :type nums: List[int]
        """
        self.nums = nums
    def reset(self):
        """
        Resets the array to its original configuration and return it.
        :rtype: List[int]
        """
        return self.nums
    def shuffle(self):
        """
        Returns a random shuffling of the array.
        :rtype: List[int]
        """
        array=copy.copy(self.nums)
        for i in range(len(array)):
            random_num = random.randint(i,len(array)-1)
            array[i], array[random_num] = array[random_num], array[i]
        return array
# Your Solution object will be instantiated and called as such:
# obj = Solution(nums)
# param_1 = obj.reset()
# param_2 = obj.shuffle()

蓄水池抽样

以下两个题都是k=1的情况,池子容量为1。

382. 链表随机节点

蓄水池抽样算法的思路:

思路:

数组容量为n,池子容量为k。

先把前k个元素放进池子里。从第k+1个元素开始,生成[0,k+1]的随机数,当这个随机数落在[0,k]区间时,替换之。

证明:

如何理解上述过程的概率公式呢?

当走到k+1步时,

当这个随机数落在[0,k]区间的时候,概率是k/k+1。

从[0,k]之间随机选一个元素,概率是1/k。

因此,这个池子里的元素i,被k+1个元素替换的概率是k/k+1 * 1/k = 1/k+1,

则被保留的概率是1-1/(k+1)=k/(k+1)。

当走到n步时,

池子里的元素i被保留的概率是k/n。保证了采样的均匀性。

海量数据随机抽样

蓄水池采样算法(Reservoir Sampling) - alfred_zhong - 博客园

蓄水池抽样算法(Reservoir Sampling) - 简书

链表随机节点

生成k到i的随机数,如果随机数在k范围内,就替换池子里的数。

class Solution(object):
    def __init__(self, head):
        self.head = head
    def getRandom(self):
        count = 0
        reserve = 0
        cur = self.head
        while cur:
            count += 1
            rand = random.randint(1,count)
            if rand == 1:
                reserve = cur.val
            cur = cur.next
        return reserve
class Solution {
public:
    /** @param head The linked list's head.
        Note that the head is guaranteed to be not null, so it contains at least one node. */
    Solution(ListNode* head): head(head) {

    }
    
    /** Returns a random node's value. */
    int getRandom() {
        int i=2;
        ListNode* cur = head->next;
        int val = head->val;
        while(cur != nullptr) {
            if(rand() % i + 1 == 1) val = cur->val; //第 i 节点以 1/i 概率替换当前值
            i++;
            cur = cur->next;
        }
        return val;
    }
private:
    ListNode* head;
};

作者:li-zi-he
链接:https://leetcode-cn.com/problems/linked-list-random-node/solution/zhong-ju-si-wei-by-li-zi-he/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

398 随机数索引

思路:
(1)计数器count记录target值个数
(2)以1/count的概率抽样

用if random.randint(0, count) < 1来保证等概率抽样。

class Solution(object):

    def __init__(self, nums):
        self.nums = nums

    def pick(self, target):
        count = 0
        res = -1
        for i in range(len(self.nums)):
            if self.nums[i] == target:
                if random.randint(0, count) < 1:  # 以某一概率(1/count)抽样
                    res = i
                count += 1
        return res
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值