Showing posts with label Math. Show all posts
Showing posts with label Math. Show all posts

Tuesday, February 2, 2021

528. Random Pick with Weight

ou are given an array of positive integers w where w[i] describes the weight of ith index (0-indexed).

We need to call the function pickIndex() which randomly returns an integer in the range [0, w.length - 1]pickIndex() should return the integer proportional to its weight in the w array. For example, for w = [1, 3], the probability of picking the index 0 is 1 / (1 + 3) = 0.25 (i.e 25%) while the probability of picking the index 1 is 3 / (1 + 3) = 0.75 (i.e 75%).

More formally, the probability of picking index i is w[i] / sum(w).

 

Example 1:

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

Explanation
Solution solution = new Solution([1]);
solution.pickIndex(); // return 0. Since there is only one single element on the array the only option is to return the first element.

Example 2:

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

Explanation
Solution solution = new Solution([1, 3]);
solution.pickIndex(); // return 1. It's returning the second element (index = 1) that has probability of 3/4.
solution.pickIndex(); // return 1
solution.pickIndex(); // return 1
solution.pickIndex(); // return 1
solution.pickIndex(); // return 0. It's returning the first element (index = 0) that has probability of 1/4.

Since this is a randomization problem, multiple answers are allowed so the following outputs can be considered correct :
[null,1,1,1,1,0]
[null,1,1,1,1,1]
[null,1,1,1,0,0]
[null,1,1,1,0,1]
[null,1,0,1,0,0]
......
and so on.

 

Constraints:

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

 

Answer: I just copied answer with top vote. Good idea to convert scale of sum to scale 1. Please checkout my comment below. 

Btw, Random r = new Random(); r.nextInt(i); // return integer between [0, i)

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
class Solution {
    // explain probabilities[i]:
    // Math.random() is to randomly pick an value from 0 to 1
    // We need to convert from scale 1 to scale sum
    // so that any value of Math.random() corresponds to 1 portion of scale sum
    // in below formula, w[i] is the original value of w
    // probabilities[i] - probabilities[i - 1] == w[i]/sum
    // which means in portion i, its length is w[i]/sum, in the scale of 0 to 1
    // And this is the weighted probability in scale of 0 to 1 
    private double[] probabilities;
    
    public Solution(int[] w) {
        double sum = 0;
        this.probabilities = new double[w.length];
        for(int weight : w)
            sum += weight;
        for(int i = 0; i < w.length; i++){
            w[i] += (i == 0) ? 0 : w[i - 1];
            probabilities[i] = w[i]/sum; 
        }
    }
     
    public int pickIndex() {
        // Arrays.binarySearch returns the index of 1st bigger element
        return Math.abs(Arrays.binarySearch(this.probabilities, Math.random())) - 1;
    }
}

/**
 * Your Solution object will be instantiated and called as such:
 * Solution obj = new Solution(w);
 * int param_1 = obj.pickIndex();
 */


Monday, February 1, 2021

254. Factor Combinations

 Numbers can be regarded as product of its factors. For example,

8 = 2 x 2 x 2;
  = 2 x 4.

Write a function that takes an integer n and return all possible combinations of its factors.

Note:

  1. You may assume that n is always positive.
  2. Factors should be greater than 1 and less than n.

Example 1:

Input: 1
Output: []

Example 2:

Input: 37
Output:[]

Example 3:

Input: 12
Output:
[
  [2, 6],
  [2, 2, 3],
  [3, 4]
]

Example 4:

Input: 32
Output:
[
  [2, 16],
  [2, 2, 8],
  [2, 2, 2, 4],
  [2, 2, 2, 2, 2],
  [2, 4, 4],
  [4, 8]
]


My answer: didn't figure out solution, only think of sqrt() to restrict choices. Please take a look at the key point below.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
class Solution {
    public List<List<Integer>> getFactors(int n) {
        List<List<Integer>> result = new ArrayList<List<Integer>>();
        helper(2, n , new ArrayList<Integer>(), result);
        return result;
    }
    
    private void helper(int start, int n, List<Integer> singleResult, List<List<Integer>> result) {
        // we use i * i < n to make sure the 1st factor of n is in ascending order
        // and it can avoid duplicate factor
        // because the larger factor corresponding the smaller factor won't be picked
        for (int i = start; i * i <= n; i ++) {
            if (n % i == 0) {// find i as valid factor
                singleResult.add(i);
                singleResult.add(n/i);
                result.add(new ArrayList<Integer>(singleResult));
                // backtrack singleResult as we are using i as starting factor
                singleResult.remove(singleResult.size() - 1);
                // continue to get factors for n/i
                // KEY POINT: new start is i
                // because factor smaller than i must have already shown up in
                // previous recursion, no need to go over again
                helper(i, n/i, singleResult, result);
                // backtrack singleResult as we keep using i as starting factor
                singleResult.remove(singleResult.size() - 1);
            }
        }
    }
}