Randomly split a given number M into N parts - java

So, the idea that I have, is to be able to divide $2.00 into 10 person, and each of them will receive $x.xx amount of money randomly. (N and M will always be limited to 2 decimals and > 0)
Ex: {0.12, 0.24, 1.03, 0.01, 0.2, 0.04, 0.11, 0.18, 0.05, 0.02}
Currently I have tried:
private static BigDecimal[] randSum(int n, double m)
{
Random rand = new Random();
BigDecimal randNums[] = new BigDecimal[n], sum = new BigDecimal(0).setScale(2);
for (int i = 0; i < randNums.length; i++)
{
randNums[i] = new BigDecimal(rand.nextDouble()).setScale(2, RoundingMode.HALF_EVEN);
sum = sum.add(randNums[i]);
}
for (int i = 0; i < randNums.length; i++)
{
BigDecimal temp1 = randNums[i].divide(sum, 2, RoundingMode.HALF_EVEN);
BigDecimal temp2 = temp1.multiply(new BigDecimal(m).setScale(2));
randNums[i] = temp2;
}
return randNums;
}
public static void main(String[] args)
{
BigDecimal d[] = randSum(5, 2);
double sum = 0;
for (BigDecimal n : d)
{
sum += n.doubleValue();
System.out.println(n);
}
System.out.println("total: " + sum);
}
But BigDecimals are too confusing and they don't add up. Sometimes the total is 1.98 or 2.01. Doubles doesn't work because of the Double-precision floating-point.
The code was taken from:
Getting N random numbers that the sum is M

Let's suppose you need a fixed precision (passed as prec argument):
static public BigDecimal[] split(BigDecimal sum, int prec, int count) {
int s = sum.scaleByPowerOfTen(prec).intValue();
Random r = new Random();
BigDecimal[] result = new BigDecimal[count];
int[] v = new int[count];
for (int i = 0; i < count - 1; i++)
v[i] = r.nextInt(s);
v[count - 1] = s;
Arrays.sort(v);
result[0] = BigDecimal.valueOf(v[0]).scaleByPowerOfTen(-prec);
for (int i = 1; i < count; i++)
result[i] = BigDecimal.valueOf(v[i] - v[i - 1]).scaleByPowerOfTen(-prec);
return result;
}
This approach uses property that Random.nextInt() is uniformly distributed. After sorting, values of v[] array are points by which the whole amount is split, so you generate result using differences between neighboring elements:
[ 2, 5, 10, 11, ..., 197, 200] // v[]
[0.02, 0.03, 0.05, 0.01, ..., ..., 0.03] // result[]
Here you operate with integer values, so rounding issues don't bother anymore.

I suggest to multiply all the numbers by 100 and rephrase your problem: generate the n random non-negative integer numbers which sum equals to the given m integer number. Later you can divide all the generated numbers by 100 to get what you want. Here's my implementation (similar to #SashaSalauyou version):
private static int[] randSum(int n, int min, int m) {
Random rand = new Random();
int[] nums = new int[n];
int max = m - min*n;
if(max <= 0)
throw new IllegalArgumentException();
for(int i=1; i<nums.length; i++) {
nums[i] = rand.nextInt(max);
}
Arrays.sort(nums, 1, nums.length);
for(int i=1; i<nums.length; i++) {
nums[i-1] = nums[i]-nums[i-1]+min;
}
nums[nums.length-1] = max-nums[nums.length-1]+min;
return nums;
}
I also added one more parameter, min which is the minimal wanted number. Set it to 0 if you accept zeros in the answer. Otherwise you may set it to 1 (then after division by 100 the lowest possible number will be 0.01).

You can treat this problem as integers, and instead of summing to M, make it sum to 100M.
Do the algorithm, and you will end up with non-integers number, such as 10.345, Now - basically what you would like to do is take the floor value of each number (10 in the above example), and to increase the number to 11 with probability proportional to 0.345.
That can be done by creating the reminder array: rem[i] = value[i] - ceil(value[i]), and choose M - sum{ceil(value[i])} values with replacements, according to the weighted probability of rem array.
Code:
public static BigDecimal[] createRandomSumsTo(BigDecimal M, int n) {
int m = M.multiply(BigDecimal.TEN).multiply(BigDecimal.TEN).intValue();
double[] rands = new double[n];
double sum = 0;
for (int i = 0; i < n; i++) {
rands[i] = rand.nextDouble();
sum += rands[i];
}
for (int i = 0; i < n; i++) rands[i] = (rands[i] / sum) * m;
int[] intVals = new int[n];
double[] rem = new double[n];
//create base and reminder array:
for (int i =0 ; i < n; i++) {
intVals[i] = (int) Math.floor(rands[i]);
rem[i] = rands[i] - intVals[i];
}
//for efficiently chosing a random value by weight
double[] aux = new double[n+1];
for (int i = 1 ; i < n+1; i++) {
aux[i] = aux[i-1] + rem[i-1];
}
//normalize to sum to one.
for (int i = 0 ; i < n+1; i++) {
aux[i] = aux[i] / aux[n];
}
int intsSum = 0;
for (int x : intVals) {
intsSum += x;
}
for (; intsSum < m; intsSum++) {
intVals[chooseWeighted(aux)]++;
}
//and create the BigDecimal array:
BigDecimal[] res = new BigDecimal[n];
for (int i = 0; i < n; i++) {
res[i] = new BigDecimal(intVals[i]).divide(BigDecimal.TEN).divide(BigDecimal.TEN);
}
return res;
}
private static int chooseWeighted(double[] probabilities) {
double r = rand.nextDouble();
int idx = Arrays.binarySearch(probabilities, r);
if (idx >= 0) return idx-1;
return (-1*idx) -2;
}

Related

Fill an array with powers of 3

public class Power {
public static void main(String[] args) {
int base = 3, exponent = 9;
int[] result = new int[10];
System.out.println(result);
while (exponent != 0)
{
result * base = result;
--exponent;
System.out.println(result);
}
}
}
What I would like this code to do is be able to Multiply 1*3 to make 3, put it inside of the array, and multiply it again, and so on and so forth. Basically, it needs to output, 1 3 9 27 81 243 729 2187 6561 19683. How can I store it inside of the array, and also multiply it again?
You could keep a result variable and continue saving it to an array:
int index = 0;
int[] result = new int[10];
int current = 1;
for (int i = 0; i < result.length; ++i) {
result[i] = current;
current *= 3;
}
System.out.println(Arrays.asString(result));
result[0] = 1;
System.out.print(result[0] + " ");
for (int i = 1; i < n; i++) {
result[i] = result[i-1]*3;
System.out.print(result[i] + " ");
}
Let n be one less than the number of entries you want to print.
Your first problem is that assignments need the name on the left side, and the expression on the right side; replace result * base = result; by result = result * base;.
Secondly, result is an array. You’re trying to treat it as a single number.
Thirdly, if you want to fill an array, use a for loop instead of what you currently have:
final int base = 3;
final int[] result = new int[10];
result[0] = 1;
for (int i = 1; i < result.length; i++) {
result[i] = result[i - 1] * base;
}

Is there is way I can solve this question in nlogn complexity

You are given a sequence of N integers A denoted by A[1] , A[2]…..A[N].
Each integer in the sequence has a value associated with it W[1],W[2]…. W[N].
You have to select a subsequence of given array A such that all the elements in A are in strictly increasing order and sum of values of elements in this selected subsequence is maximum. You have to print this maximum value.
Sample Input
2
4
1 2 3 4
100 200 300 400
3
4 2 3
100 30 20
Sample Output
1000
100
I tried to solve this problem using dynamic programming but the time complexity of my code is n^2 so i want to reduce its complexity to nlogn can you help me?
Here is my implementation:
public class testing {
public static void main(String[] args) {
Scanner scn = new Scanner(System.in);
int t = scn.nextInt();
StringBuilder sb = new StringBuilder();
while (t-- > 0) {
int n = scn.nextInt();
int a[] = new int[n];
long val[] = new long[n];
for (int i = 0; i < n; i++) {
a[i] = scn.nextInt();
}
for (int i = 0; i < n; i++) {
val[i] = scn.nextLong();
}
long dp[] = new long[n];
Arrays.fill(dp, Integer.MIN_VALUE);
dp[0] = val[0];
for (int i = 1; i < n; i++) {
for (int j = i - 1; j >= 0; j--) {
if (a[j] < a[i]) {
dp[i] = Math.max(dp[i], dp[j] + val[i]);
}
}
}
long ans = Integer.MIN_VALUE;
for (long v : dp) {
ans = Math.max(v, ans);
}
sb.append(ans + "\n");
}
System.out.println(sb);
}
}
I am getting TLE because of contraints
Constraints
1 <= T <= 5 1 <= N <= 200000 1 <= a[i] <= 10^9, where i ∈ [1..N] 1 <= w[i] <= 10^9, where i ∈ [1..N]
Iterate once, and maintain a TreeMap of the sum of W values for A values less than or equal to the given A, as seen at the time you iterated over the A value.
For a new A, call the lowerEntry(key) method for the sum of W's below that new A.
Remember the largest sum, and return that.
Single iteration is O(n), and TreeMap use is O(log n), so solution is O(n log n)*.
static int sumIncreasing(int[] a, int[] w) {
int maxSum = Integer.MIN_VALUE;
TreeMap<Integer, Integer> sums = new TreeMap<>();
for (int i = 0; i < a.length; i++) {
Entry<Integer, Integer> lowerSum = sums.lowerEntry(a[i]);
int sum = (lowerSum != null ? lowerSum.getValue() + w[i] : w[i]);
sums.put(a[i], sum);
for (Entry<Integer, Integer> e; (e = sums.higherEntry(a[i])) != null && e.getValue() <= sum; )
sums.remove(e.getKey());
if (sum > maxSum)
maxSum = sum;
}
return maxSum;
}
*) The inner for loop is O(log n) (amortized, worst case), so it doesn't affect overall complexity.
Test
System.out.println(sumIncreasing(new int[] {1, 2, 3, 4}, new int[] {100, 200, 300, 400}));
System.out.println(sumIncreasing(new int[] {4, 2, 3}, new int[] {100, 30, 20}));
Output
1000
100

Sum of digits in random generated arrays

I know this may stand for a silly question but I have got a lot of problems with this.
I will first explain how it should work :
1)Generate random Array with size in range <4,7>
2)Fill it with random elements in range <100, 999>
3)Print the index of three numbers with biggest digit sum
So the question is-how? I know I should implement this:
SumOfDigits += ElementFromArray % 10;
ElementFromArray /= 10;
But i have got no idea where. I tried to add this as a if (i>0) loop inside for loop-but its not working.
Also how at the end im going to print the proper elements? Should I use Arrays.sort(tab) and then System.out.println(tab[tab.length - 1]) (and so on with -2, -3 for 3 last elements)?
import java.util.Arrays;
import java.util.Random;
public class Ex1 {
public static void main(String[] args) {
Random rand = new Random();
int size = rand.nextInt(4) + 4;
int tab[] = new int[size];
for (int i = 0; i < tab.length; i++) {
int elements = rand.nextInt(900) + 100;
tab[i] = elements;
}
System.out.println(Arrays.toString(tab));
}
}
If we aim for a solution using only arrays I would use a 2d array to hold the sum of digits and the index of the corresponding number in the tab array
So first create the array based on the size of the original array
int[][] sums = new int[size][2];
then in the for loop, calculate the sum of the random number and store it and the index
sums[i][0] = elements / 100 + (elements / 10) % 10 + elements % 10;
sums[i][1] = i;
Then sort the sums array using a custom comparator
Arrays.sort(sums, new Comparator<int[]>() {
#Override
public int compare(int[] o1, int[] o2) {
return Integer.compare(o2[0], o1[0]);
}
});
And finally print the index and number of the numbers of the top 3
for (int i = 0; i < 3; i++) {
System.out.printf("%d: %d\n", sums[i][1], tab[sums[i][1]]);
}
Just use while loop: here is a quick and dirty solution:
private static void main10(String[] args) {
Random rand = new Random();
int size = rand.nextInt(4) + 4;
int[] tab = new int[size];
for (int i = 0; i < tab.length; i++) {
int element = rand.nextInt(900) + 100;
tab[i] = element;
}
System.out.println(Arrays.toString(tab));
// calculate digits:
int[] digitsums = new int[size];
for (int i = 0; i < tab.length; i++) {
int element = tab[i];
int sumOfDigits = 0;
while (element > 0) {
sumOfDigits += element % 10;
element /= 10;
}
digitsums[i] = sumOfDigits;
}
System.out.println(Arrays.toString(digitsums));
int[] copyOfdigitsums = Arrays.copyOf(digitsums, digitsums.length);
for (int i = 1; i <= 3; i++) {
int j = getIndexOfLargest(copyOfdigitsums);
System.out.println("index of " + i + "largest is " + j + ", with a digitsum of " + copyOfdigitsums[j]);
copyOfdigitsums[j] = 0;
}
}
static int getIndexOfLargest(int[] digitsums) {
int largest = 0;
int index = 0;
for (int i = 0; i < digitsums.length; i++) {
int d = digitsums[i];
if (largest < d) {
largest = d;
index = i;
}
}
return index;
}

Generate random numbers from 0 to 7 with every number appearing 2 times in java ADT

I need to generate random numbers from 0 to 7 with every number appearing 2 times. The end result should have every number appearing 2 times, in random order. An example would be:
MyArray = [3, 6, 0, 5, 2, 2, 6, 7, 5, 4, 7, 1, 3, 1, 0, 4]
This is what I tried to do. The code works alone but not in an ADT environnement (in an adapter class that is visited 16 times, but only 14 when I use this code).
ArrayList<Integer> nombres = new ArrayList<Integer>();
private int getRandomNumber() {
Random rand = new Random();
int temp;
while(true){
temp = rand.nextInt(8);
if (nombres.size()==0) {
nombres.add(temp);
return temp;
}
if (nombres.contains(temp)){
if (nombres.indexOf(temp) == nombres.lastIndexOf(temp)){
nombres.add(temp);
return temp;
}
}
if (!nombres.contains(temp)){
nombres.add(temp);
return temp;
}
}
}
Any other, easier solutions? (I have tried to put everything in a single if, same result).
A straightforward way is to do it with Collections.shuffle().
Pseudocode:
for(0 to 7)
myArrayList.add(num);
myArrayList.add(num);
Collections.shuffle(myArrayList);
// Convert to array if necessary
Adding all the numbers and then using Collections.shuffle would probably be easiest.
List<Integer> generateRandomArray(int max) {
List<Integer> result = new ArrayList<Integer>();
for(int i = 0; i <= max; i++) {
result.add(i);
result.add(i);
}
Collections.shuffle(result);
return result;
}
A much simpler way is to populate the results first, then serve them out:
List<Integer> nombres = new ArrayList<Integer>();
int index;
private int getRandomNumber() {
if (nombres.isEmpty()) {
for (int i = 0; i < 8; i++) {
nombres.add(i);
nombres.add(i);
}
Collections.shuffle(nombres);
}
if (index >= nombres.size())
throw new IllegalStateException();
return nombres.get(index++);
}
Using unique numbers this way is inefficient in general.
A better way to do this is first generating the array of integers and then using swap operations to generate a random list:
int n = 8;//maximum bound (exclusive)
int s = 2*n;
Random rand = new Random();
int[] result = new int[s];
for(int i = 0, j = 0; i < n; i++) {
result[j++] = i;
result[j++] = i;
}
for(int i = 0; i < s; i++) {
int j = i + rand.nextInt(s-i);
int temp = result[i];
result[i] = result[j];
result[j] = temp;
}
Or its equivalent for ArrayList<Integer>:
int n = 8;//maximum bound (exclusive)
int s = 2*n;
Random rand = new Random();
ArrayList<Integer> result = new ArrayList<Integer>();
for(int i = 0, j = 0; i < n; i++) {
result.add(i);
result.add(i);
}
for(int i = 0; i < s; i++) {
int j = i + rand.nextInt(s-i);
int temp = result.get(i);
result.set(i,result[j]);
result.set(j,temp);
}

Java: Array with loop

I need to create an array with 100 numbers (1-100) and then calculate how much it all will be (1+2+3+4+..+100 = sum).
I don't want to enter these numbers into the arrays manually, 100 spots would take a while and cost more code.
I'm thinking something like using variable++ till 100 and then calculate the sum of it all. Not sure how exactly it would be written.
But it's in important that it's in arrays so I can also say later, "How much is array 55" and I can could easily see it.
Here's how:
// Create an array with room for 100 integers
int[] nums = new int[100];
// Fill it with numbers using a for-loop
for (int i = 0; i < nums.length; i++)
nums[i] = i + 1; // +1 since we want 1-100 and not 0-99
// Compute sum
int sum = 0;
for (int n : nums)
sum += n;
// Print the result (5050)
System.out.println(sum);
If all you want to do is calculate the sum of 1,2,3... n then you could use :
int sum = (n * (n + 1)) / 2;
int count = 100;
int total = 0;
int[] numbers = new int[count];
for (int i=0; count>i; i++) {
numbers[i] = i+1;
total += i+1;
}
// done
I'm not sure what structure you want your resulting array in, but the following code will do what I think you're asking for:
int sum = 0;
int[] results = new int[100];
for (int i = 0; i < 100; i++) {
sum += (i+1);
results[i] = sum;
}
Gives you an array of the sum at each point in the loop [1, 3, 6, 10...]
To populate the array:
int[] numbers = new int[100];
for (int i = 0; i < 100; i++) {
numbers[i] = i+1;
}
and then to sum it:
int ans = 0;
for (int i = 0; i < numbers.length; i++) {
ans += numbers[i];
}
or in short, if you want the sum from 1 to n:
( n ( n +1) ) / 2
If your array of numbers always is starting with 1 and ending with X then you could use the following formula:
sum = x * (x+1) / 2
from 1 till 100 the sum would be 100 * 101 / 2 = 5050
this is actually the summation of an arithmatic progression with common difference as 1. So this is a special case of sum of natural numbers. Its easy can be done with a single line of code.
int i = 100;
// Implement the fomrulae n*(n+1)/2
int sum = (i*(i+1))/2;
System.out.println(sum);
int[] nums = new int[100];
int sum = 0;
// Fill it with numbers using a for-loop
for (int i = 0; i < nums.length; i++)
{
nums[i] = i + 1;
sum += n;
}
System.out.println(sum);
The Array has declared without intializing the values and if you want to insert values by itterating the loop this code will work.
Public Class Program
{
public static void main(String args[])
{
//Array Intialization
int my[] = new int[6];
for(int i=0;i<=5;i++)
{
//Storing array values in array
my[i]= i;
//Printing array values
System.out.println(my[i]);
}
}
}

Categories

Resources