How to choose a random number in a weighted way - java

For example if I have an array of ints like this:
int[] list = {1, 4, 2};
And I want to choose one of these 3 numbers, but have the greater values get chosen more frequently:
1 get chosen 1/7 of the time
4 gets chosen 4/7 of the time
2 gets chosen 2/7 of the time
How can I write a function for this, if there isn't already one in Java.
Edit: I'm looking for an efficient solution, O(n) or better.
I'm going to be running this code a lot times in many threads. Building a new list is not sufficient.

Accumulate the values in list and call the resulting sum S. Now generate a random number from 0 to S - 1. Iterate once more over list and for each element do the following: if the element is greater then S than choose that element. Otherwise decrease S by the element's value and continue on to the next element.

You can simply use Math.random() to get a random number in the range of 0..1, and choose the number at the index whose cumulative weights "cover" the random number:
public static int random(int[] numbers, double[] weights) {
double r = Math.random();
double sum = 0;
for (int i = 0; i < weights.length; i++) {
sum += weights[i];
if (r < sum)
return numbers[i];
}
return 0; // You can only get here if sum weights is less than 1
}
This solution chooses you a random number according to the weights you provide in O(N). In most cases the algorithm doesn't even read the whole weights array. This is as good as it can get. Maximum steps is N, average number of steps is N/2.
Notes:
On average the method will be faster if bigger weights are at the beginning of the weights array.
The sum of the weights is expected to be 1. If the sum of the weights is less than
1, this method might return 0 (with a probability of 1-sum(weights)).

1) Take the sum(S) of elements(A[i])
2) Get Cumulative sum list(C[i])
3) Get Random Value(R) from 0 to S-1
4) If R < C[i], your random value is A[i]
Cumulative Sum Range Index in the Cumulative Array Value in Original Array
----------------- ----------------------------- ----------------------
0 <= x < 1 0 1
1 <= x < 6 1 4
6 <= x < 7 2 2

Related

Finding all permutations to get the given sum (Coin change problem)

I am trying to solve a classical coin-change (dynamic) problem.
To find number of all unique combinations to get a sum from infinite denominations of coins using dynamic approach, i used this method:
/*
n - number of coins
arr[] - coin denominations
x - total sum
dp[] - array to store number of combinations at index i.
*/
for (int j = 0; j < n; j++)
for (int i = 1; i <= x; i++)
if (arr[j] <= i)
dp[i] = (long) ((dp[i] + dp[i - arr[j]]) % (1e9 + 7));
This gives me all unique possible combinations count:
Eg:
Input:
n=3 x=9
Coins: 2 3 5
Output:
3
So far ,all good.
But i observed that just by interchanging the loops in above snippet, i get all the possible permutations.
for (int i = 1; i <= x; i++)
for (int j = 0; j < n; j++)
if (arr[j] <= i)
dp[i] = (long) ((dp[i] + dp[i - arr[j]]) % (1e9 + 7));
This gives me all unique possible permutations count:
Eg:
Input:
3 9
2 3 5
Output:
8
With debugging and going through each iteration, i mapped a pattern that was formed, but didn't understand the reason behind why i am getting permutations.
Can any one explain me this iteratively. Any help will be appreciated.
Thanks
Both questions can be found here:
Permutations: Coin Combinations 1
Combinations: Coin Combinations 2
The first code with outer loop by coins updates number of ways to compose values dp[] with new coin at every round of outer loop. So after k-th round we have dp[] array filled with combinations of k coins only, and the rest of coins is not used yet. If we will store combinations themselves for sorted coin array, we will see only ordered ones like 1 1 5, and 5 never will go before 1. That is why combinations.
The second code at m-th round of outer loop fills m-th cell dp[m] using all possible coins. So we count for m=7 both 1 1 5 and 1 5 1 and 5 1 1 variants. That is why all permutations are counted here.
In addition for comment: we can make 2d array, where dp[x][c] contains number of permutations with sum x, ending with coin a[c]. Note that in this case we have to join counts of permutations with sum x-a[c]. For reference - 1d and 2d Python code.
def coins1(a, n): #permutations
count = [1]+[0]*n
for x in range(1, n + 1):
for c in a:
if (x-c >= 0):
count[x] += count[x-c]
return count[n]
def coins11(a, n): #permutations 2d
m = len(a)
count = [[1] + [0]*(m-1)] + [[0]*m for i in range(n)]
for x in range(1, n + 1):
for c in range(m):
if x>=a[c]:
count[x][c] += sum(count[x-a[c]])
return sum(count[n])

Meaning of the formula how to find lost element in array?

The task is to find lost element in the array. I understand the logic of the solution but I don't understand how does this formula works?
Here is the solution
int[] array = new int[]{4,1,2,3,5,8,6};
int size = array.length;
int result = (size + 1) * (size + 2)/2;
for (int i : array){
result -= i;
}
But why we add 1 to total size and multiply it to total size + 2 /2 ?? In all resources, people just use that formula but nobody explains how that formula works
The sum of the digits 1 thru n is equal to ((n)(n+1))/2.
e.g. for 1,2,3,4,5 5*6/2 = 15.
But this is just a quick way to add up the numbers from 1 to n. Here is what is really going on.
The series computes the sum of 1 to n assuming they all were present. But by subtracting each number from that sum, the remainder is the missing number.
The formula for an arithmetic series of integers from k to n where adjacent elements differ by 1 is.
S[k,n] = (n-k+1)(n+k)/2
Example: k = 5, n = 10
S[k,n] = 5 6 7 8 9 10
S[k,n] = 10 9 8 7 6 5
S[k,n] = (10-5+1)*(10+5)/2
2S[k,n] = 6 * 15 / 2
S[k,n] = 90 / 2 = 45
For any single number missing from the sequence, by subtracting the others from the sum of 45, the remainder will be the missing number.
Let's say you currently have n elements in your array. You know that one element is missing, which means that the actual size of your array should be n + 1.
Now, you just need to calculate the sum 1 + 2 + ... + n + (n+1).
A handy formula for computing the sum of all integers from 1 up to k is given by k(k+1)/2.
By just replacing k with n+1, you get the formula (n+1)(n+2)/2.
It's simple mathematics.
Sum of first n natural numbers = n*(n+1)/2.
Number of elements in array = size of array.
So, in this case n = size + 1
So, after finding the sum, we are subtracting all the numbers from array individually and we are left with the missing number.
Broken sequence vs full sequence
But why we add 1 to total size and multiply it to total size + 2 /2 ?
The amount of numbers stored in your array is one less than the maximal number, as the sequence is missing one element.
Check your example:
4, 1, 2, 3, 5, 8, 6
The sequence is supposed to go from 1 to 8, but the amount of elements (size) is 7, not 8. Because the 7 is missing from the sequence.
Another example:
1, 2, 3, 5, 6, 7
This sequence is missing the 4. The full sequence would have a length of 7 but the above array would have a length of 6 only, one less.
You have to account for that and counter it.
Sum formula
Knowing that, the sum of all natural numbers from 1 up to n, so 1 + 2 + 3 + ... + n can also be directly computed by
n * (n + 1) / 2
See the very first paragraph in Wikipedia#Summation.
But n is supposed to be 8 (length of the full sequence) in your example, not 7 (broken sequence). So you have to add 1 to all the n in the formula, receiving
(n + 1) * (n + 2) / 2
I guess this would be similar to Missing Number of LeetCode (268):
Java
class Solution {
public static int missingNumber(int[] nums) {
int missing = nums.length;
for (int index = 0; index < nums.length; index++)
missing += index - nums[index];
return missing;
}
}
C++ using Bit Manipulation
class Solution {
public:
int missingNumber(vector<int> &nums) {
int missing = nums.size();
int index = 0;
for (int num : nums) {
missing = missing ^ num ^ index;
index++;
}
return missing;
}
};
Python I
class Solution:
def missingNumber(self, nums):
return (len(nums) * (-~len(nums))) // 2 - sum(nums)
Python II
class Solution:
def missingNumber(self, nums):
return (len(nums) * ((-~len(nums))) >> 1) - sum(nums)
Reference to how it works:
The methods have been explained in the following links:
Missing Number Discussion
Missing Number Solution

How would I loop over the permutations of N numbers with a given range, preferably without recursion?

I have N numbers, and a range, over which I have to permute the numbers.
For example, if I had 3 numbers and a range of 1-2, I would loop over 1 1 1, 1 1 2, 1 2 1, etc.
Preferably, but not necessarily, how could I do this without recursion?
For general ideas, nested loops don't allow for an arbitrary number of numbers, and recursion is undesireable due to high depth (3 numbers over 1-10 would be over 1,000 calls to the section of code using those numbers)
One way to do this, is to loop with one iteration per permuation, and use the loop variable to calculate the values that a permuation is made off. Consider that the size of the range can be used as a modulo argument to "chop off" a value (digit) that will be one of the values (digits) in the result. Then if you divide the loop variable (well, a copy of it) by the range size, you repeat the above operation to extract another value, ...etc.
Obviously this will only work if the number of results does not exceed the capacity of the int type, or whatever type you use for the loop variable.
So here is how that looks:
int [][] getResults(int numPositions, int low, int high) {
int numValues = high - low + 1;
int numResults = (int) Math.pow(numValues, numPositions);
int results[][] = new int [numResults][numPositions];
for (int i = 0; i < numResults; i++) {
int result[] = results[i];
int n = i;
for (int j = numPositions-1; j >= 0; j--) {
result[j] = low + n % numValues;
n /= numValues;
}
}
return results;
}
The example you gave in the question would be generated with this call:
int results[][] = getResults(3, 1, 2);
The results are then:
1 1 1
1 1 2
1 2 1
1 2 2
2 1 1
2 1 2
2 2 1
2 2 2

Why does my code fail the hidden input test cases?

This is the problem to be solved:
John is assigned a new task today. He is given an array A containing N integers. His task is to update all elements of array to some minimum value x , that is, A[i] = x; 1 <= i <= N; such that sum of this new array is strictly greater than the sum of the initial array.
Note that x should be as minimum as possible such that the sum of the new array is greater than the sum of the initial array.
Input Format:
First line of input consists of an integer N denoting the number of elements in the array A.
Second line consists of N space separated integers denoting the array elements.
Output Format:
The only line of output consists of the value of x.
Sample Input:
5
12345
Sample Output:
4
Explanation:
Initial sum of array= 1 + 2 + 3 + 4 + 5 = 15
When we update all elements to 4, sum of array = 4 + 4 + 4 + 4 + 4 = 20 which is greater than 15.
Note that if we had updated the array elements to 3, sum = 15 which is not greater than 15. So, 4 is the minimum value to which array elements need to be updated.
** ==> Here is my code. How can I improve it? or What is the problem in this code? **
import java.util.Scanner;
public class Test2 {
public static void main(String []args){
Scanner s=new Scanner(System.in);
int check=0, sum=0, biggest=0;
int size=s.nextInt();
if(size>=1 && size<=100000) {
int[] arr=new int[size];
for(int i=0; i<size; i++){
int temp=s.nextInt();
if(temp>=1 && temp<=1000) {
arr[i] = temp;
biggest=biggest > temp ? biggest:temp;
sum=sum+temp;
}
else break;
}
for(int i=1; i<biggest; i++){
check=(size*i)>sum ? i:0;
}
System.out.print(check);
}
else System.err.print("Invalid input size");
}
}
Issue:
for(int i=1; i<biggest; i++){
check=(size*i)>sum ? i:0;
}
There are 2 problems with this, hence it doesn't work. They are as follows-
(size*i)>sum ? i - The problem statement states that it needs minimum possible sum greater than sum of array of elements. Your code blindly assigns i to check without checking the minimality.
check=(size*i)>sum ? i:0 - So, even if you had come across some integer previously, you lost it because you assigned it to 0 if the condition is not satisfied.
I will share my idea of how would I go about this.
Approach 1
Sum all elements like you did.
Now, take average of elements - sum / size of the array. Let's say we store it in a variable average.
Print average + 1 as your answer, as that is the value that could give you minimum possible sum > sum of array itself.
Time Complexity: O(n), where n is size of the array.
Space Complexity: O(1)
Approach 2
Sum all elements like you did.
Calculate min and max for the array and store it in variables, say mini and maxi.
Now, do a binary search between mini and maxi and keep checking the minimum sum > sum criteria.
In this process, you will have variables like low, mid and high.
low = mini,high = maxi
while low <= high:
mid = low + (high - low) / 2
If mid * size <= sum,
low = mid + 1
else
high = mid - 1
Now, print low as your answer.
Let range = maxi - mini.
Time Complexity: O(n) + O(log(range)) = O(n) asymptotically, where n is size of the array.
Space Complexity: O(1)
Not sure if I completely followed what your attempt was, but there should be a pretty straightfoward solution. You know the size of the array and you can easily iterate through the array to get the value of the elements stored in it. All you need to do to find your min x is to take sumOfArray/size of array and then add one to the result to make your result higher.
In your example 15/5=3. 3+1 = 4 so that's your answer. If the numbers summed to 43, 43/5 = 8 r 3, so your answer is 9 (9*5=45). Etc.
When trying some other test cases, then the results are wrong. Try:
Input:
5
1 1 1 1 5
Expected Output: 2 Actual Output: 4
and
Input:
5
5 5 5 5 5
Expected Output: 6 Actual Output: 0

Generating N numbers that sum to 1

Given an array of size n I want to generate random probabilities for each index such that Sigma(a[0]..a[n-1])=1
One possible result might be:
0 1 2 3 4
0.15 0.2 0.18 0.22 0.25
Another perfectly legal result can be:
0 1 2 3 4
0.01 0.01 0.96 0.01 0.01
How can I generate these easily and quickly? Answers in any language are fine, Java preferred.
Get n random numbers, calculate their sum and normalize the sum to 1 by dividing each number with the sum.
The task you are trying to accomplish is tantamount to drawing a random point from the N-dimensional unit simplex.
http://en.wikipedia.org/wiki/Simplex#Random_sampling might help you.
A naive solution might go as following:
public static double[] getArray(int n)
{
double a[] = new double[n];
double s = 0.0d;
Random random = new Random();
for (int i = 0; i < n; i++)
{
a [i] = 1.0d - random.nextDouble();
a [i] = -1 * Math.log(a[i]);
s += a[i];
}
for (int i = 0; i < n; i++)
{
a [i] /= s;
}
return a;
}
To draw a point uniformly from the N-dimensional unit simplex, we must take a vector of exponentially distributed random variables, then normalize it by the sum of those variables. To get an exponentially distributed value, we take a negative log of uniformly distributed value.
This is relatively late, but to show the ammendment to #Kobi's simple and straightforward answer given in this paper pointed to by #dreeves which makes the sampling uniform. The method (if I understand it clearly) is to
Generate n-1 distinct values from the range [1, 2, ... , M-1].
Sort the resulting vector
Add 0 and M as the first and last elements of the resulting vector.
Generate a new vector by computing xi - xi-1 where i = 1,2, ... n. That is, the new vector is made up of the differences between consecutive elements of the old vector.
Divide each element of the new vector by M. You have your uniform distribution!
I am curious to know if generating distinct random values and normalizing them to 1 by dividing by their sum will also produce a uniform distribution.
Get n random numbers, calculate their sum and normalize the sum to 1
by dividing each number with the sum.
Expanding on Kobi's answer, here's a Java function that does exactly that.
public static double[] getRandDistArray(int n) {
double randArray[] = new double[n];
double sum = 0;
// Generate n random numbers
for (int i = 0; i < randArray.length; i++) {
randArray[i] = Math.random();
sum += randArray[i];
}
// Normalize sum to 1
for (int i = 0; i < randArray.length; i++) {
randArray[i] /= sum;
}
return randArray;
}
In a test run, getRandDistArray(5) returned the following
[0.1796505603694718, 0.31518724882558813, 0.15226147256596428, 0.30954417535503603, 0.043356542883939767]
If you want to generate values from a normal distribution efficiently, try the Box Muller Transformation.
public static double[] array(int n){
double[] a = new double[n];
double flag = 0;
for(int i=0;i<n;i++){
a[i] = Math.random();
flag += a[i];
}
for(int i=0;i<n;i++) a[i] /= flag;
return a;
}
Here, at first a stores random numbers. And the flag will keep the sum all the numbers generated so that at the next for loop the numbers generated will be divided by the flag, which at the end the array will have random numbers in probability distribution.

Categories