[LeetCode] Random Pick with Weight 根據權重隨機取點

 

Given an array w of positive integers, where w[i] describes the weight of index i, write a function pickIndex which randomly picks an index in proportion to its weight.html

Note:數組

  1. 1 <= w.length <= 10000
  2. 1 <= w[i] <= 10^5
  3. pickIndex will be called at most 10000 times.

Example 1:app

Input: 
["Solution","pickIndex"]
[[[1]],[]] Output: [null,0] 

Example 2:dom

Input: 
["Solution","pickIndex","pickIndex","pickIndex","pickIndex","pickIndex"]
[[[1,3]],[],[],[],[],[]] Output: [null,0,1,1,1,0]

Explanation of Input Syntax:函數

The input is two lists: the subroutines called and their arguments. Solution's constructor has one argument, the array wpickIndex has no arguments. Arguments are always wrapped with a list, even if there aren't any.spa

 

這道題給了一個權重數組,讓咱們根據權重來隨機取點,如今的點就不是隨機等機率的選取了,而是要根據權重的不一樣來區別選取。好比題目中例子2,權重爲 [1, 3],表示有兩個點,權重分別爲1和3,那麼就是說一個點的出現機率是四分之一,另外一個出現的機率是四分之三。因爲咱們的rand()函數是等機率的隨機,那麼咱們如何纔能有權重的隨機呢,咱們可使用一個trick,因爲權重是1和3,相加爲4,那麼咱們如今假設有4個點,而後隨機等機率取一個點,隨機到第一個點後就表示原來的第一個點,隨機到後三個點就表示原來的第二個點,這樣就能夠保證有權重的隨機啦。那麼咱們就能夠創建權重數組的累加和數組,好比若權重數組爲 [1, 3, 2] 的話,那麼累加和數組爲 [1, 4, 6],整個的權重和爲6,咱們 rand() % 6,能夠隨機出範圍 [0, 5] 內的數,隨機到 0 則爲第一個點,隨機到 1,2,3 則爲第二個點,隨機到 4,5 則爲第三個點,因此咱們隨機出一個數字x後,而後再累加和數組中查找第一個大於隨機數x的數字,使用二分查找法能夠找到第一個大於隨機數x的數字的座標,即爲所求,參見代碼以下:code

 

解法一:htm

class Solution {
public:
    Solution(vector<int> w) {
        sum = w;
        for (int i = 1; i < w.size(); ++i) {
            sum[i] = sum[i - 1] + w[i];
        }
    }
    
    int pickIndex() {
        int x = rand() % sum.back(), left = 0, right = sum.size() - 1;
        while (left < right) {
            int mid = left + (right - left) / 2;
            if (sum[mid] <= x) left = mid + 1;
            else right = mid;
        }
        return right;
    }
    
private:
    vector<int> sum;
};

 

咱們也能夠把二分查找法換爲STL內置的upper_bound函數,根據上面的分析,咱們隨機出一個數字x後,而後再累加和數組中查找第一個大於隨機數x的數字,使用二分查找法能夠找到第一個大於隨機數x的數字的座標。而upper_bound() 函數恰好就是查找第一個大於目標值的數,lower_bound() 函數是找到第一個不小於目標值的數,用在這裏就不太合適了,關於二分搜索發的分類能夠參見博主以前的博客LeetCode Binary Search Summary 二分搜索法小結,參見代碼以下:blog

 

解法二:ci

class Solution {
public:
    Solution(vector<int> w) {
        sum = w;
        for (int i = 1; i < w.size(); ++i) {
            sum[i] = sum[i - 1] + w[i];
        }
    }
    
    int pickIndex() {
        int x = rand() % sum.back();
        return upper_bound(sum.begin(), sum.end(), x) - sum.begin();
    }
    
private:
    vector<int> sum;
};

 

討論:這題有個很好的follow up,就是說當weights數組常常變換怎麼辦,那麼這就有涉及到求變化的區域和問題了,在博主以前的一道 Range Sum Query - Mutable 中有各類方法詳細的講解。只要把兩道題的解法的精髓融合到一塊兒就好了,能夠參見論壇上的這個帖子

 

相似題目:

Random Pick Index

Random Pick with Blacklist 

Random Point in Non-overlapping Rectangles

 

參考資料:

https://leetcode.com/problems/random-pick-with-weight/discuss/154024/JAVA-8-lines-TreeMap

https://leetcode.com/problems/random-pick-with-weight/discuss/154772/C%2B%2B-concise-binary-search-solution

https://leetcode.com/problems/random-pick-with-weight/discuss/154044/Java-accumulated-freq-sum-and-binary-search

 

LeetCode All in One 題目講解彙總(持續更新中...)

相關文章
相關標籤/搜索