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