Generating Random Numbers from 1-100 - java

int getnum50()
{
Random rand = new Random();
return (1+rand.nextInt(50));
}
You are given a predefined function named getnum50() which returns an
integer which is one random number from 1-50.
You can call this function as many times as you want but beware
that this function is quite resource intensive.
You cannot use any other random generator. You can NOT change the
definition of getnum50().
Print numbers 1-100 in random order. (Not 100 random numbers)
Note:
i. Every number should be printed exactly once.
ii. There should be no pattern in the numbers listing. List should be
completely random i.e., all numbers have equal probability
appearing at any place.
iii. You may call getnum50() any number of time to get random number
from 1 to 50 but try to make the code optimised.
iv. You cannot use any other random generator function except
getnum50().
I wrote some code which was showing correct output.
import java.util.Random;
public class RandomInteger{
int number[]=new int[100];//To store numbers in random order
public RandomInteger(){
int n[]=new int[100];//array to store which random numbers are generated
int off[]={-1,0};//offset to add
System.out.println("Length of array number100 is:"+number.length);
System.out.println("Generating random numbers in the range 1-100:");
for(int n1=0;n1<number.length;n1++){
int rnd=off[(getnum50()-1)/50]+(getnum50()*2);
if(n[rnd-1] == 0){
n[rnd-1]=1;//to indicate which random number is generated
number[n1]=rnd;
System.out.println(number[n1]+" ");
}
}
}
//end of constructor
int getnum50(){
Random rand = new Random();
return (1+rand.nextInt(50));
}
public static void main(String args[]){
RandomInteger m= new RandomInteger();
}
//end of main()
}
//end of class
While it was accepted in that round, in the next round the interviewer tells me that getnum50() is a costly method and even in best case scenario I have to call it twice for every number generated. i.e. 200 times for 1-100. In worst case scenario it would be infinity and tens of thousand in average case. He asks me to optimize the code so as to significantly improve the average case.
I could not answer.So please give me proper answer for the question? How will I optimize my above code??

One stupid optimization would be be to just realize that since your randomized source is limited to 1-50, you might as well set TWO array positions, e.g.
rand = getnum50();
n[rand] = 1;
n[rand+50] = 1;
Now the array will be slightly "less" random, because every index n is going simply be 1/2 of whatever's at n+50, but at least you've cut ~half the build array construction time.

I think they want you to produce a shuffle algorithm.
In this, you start with an array of exactly 100 numbers ( 1 through 100 in order ), and then on each iteration you shuffle the numbers.
Do it enough times, and the original array is completely random.

The 50 is a red herring. Use two calls to random50, mod 10. Now you have two digits: tens and ones place. This gives you a random100() function.
The real killer is the generate-and-check approach. Instead, put the numbers 1-100 into an arraylist, and use your random100 to REMOVE a random index. Now your worst case scenario has 2n calls to random50. There's a few problems left to solve - overruns - but that's the approach I'd look at.

Your problem us that if you are toward the end of the list you will have to generate lots of random numbers to get a number in the couple of spots left. You could reduce a couple of ways one the fits into your current answer fairly will is as follows:
while(n[rnd-1] == 1)
{
rnd++;
rnd=end%101;
}
n[rnd-1]=1;//to indicate which random number is generated
number[n1]=rnd;
System.out.println(number[n1]+" ");
However if you assume that the getnum50 is more expensive than anything you can write you could reduce the number of getnum50 that you call while filling in the second half of the list. Each time you find a number you could reduce your search space by one so (using non primitives):
while(myArrayList.size()>1)
{
int rnd=0;
if(myArrayList.size()>50);
rnd=((getnum50()-1)/50)+((getnum50()*2)%myArrayList.size())+1;
else
rnd=getnum50()%myArrayList.size()+1;
System.out.println(rnd);
myArrayList.remove(rnd);
}
System.out.println(myArrayList.get(rnd);
myArrayList.remove(rnd);
In this example your best, average and worst are 149 getnum50 calls;

The reason you are calling the method getnum50() twice is because of this line:
int rnd = off[(getnum50()-1)/50] + (getnum50()*2);
which seems self-explanatory. And the reason your worst case scenario is so bad is because of this block:
if(n[rnd - 1] == 0){
n[rnd - 1] = 1; //to indicate which random number is generated
number[n1] = rnd;
System.out.println(number[n1] + " ");
}
Depending on how bad your luck is, it could take a very long time to get each value. So, best case, you make your two getnum50() calls, which WILL happen the first time, but as you fill up your array, it becomes increasingly less likely. For 100 numbers, the last number will have a 1% chance of success on the first time, and every time it fails, you make another two calls to getnum50().
Sorry, this doesn't answer HOW to improve your efficiency, but it does explain why the efficiency concerns. Hope it helps.

Related

Enter 100 numbers. Determine which number is more: positive or negative

so i have this homework where i have to enter 100 numbers and after that it determines if its positive or negative, been trying for hours but still unsuccesful.
Enter 100 numbers. Determine which number is more: positive or negative. (This is literally the task and nothing more is written)
When approaching a problem, first think it thru. Then write the code.
initialize a positive or negative counter.
start reading in numbers
increment the counter based on the number's sign.
continue with (2) until 100 numbers have been read.
Print out informative information based on the results of the contents of (1) and the count of numbers read.
If you are just trying to find the highest magnitude of either positive or negative numbers you can do this quite easily by checking the absolute value:
import java.util.concurrent.ThreadLocalRandom;
public class MyClass
{
public static void main(String args[])
{
int randomNum = 0;
int largestMagnitude = 0;
for(int i = 0; i < 100; i++)
{
randomNum = ThreadLocalRandom.current().nextInt(-1000, 1000);
if(Math.abs(randomNum) > Math.abs(largestMagnitude))
{
largestMagnitude = randomNum;
}
}
System.out.println("The highest magnitude of number generated was " + largestMagnitude);
}
}
This is an suggestion to people providing answers. When the problem is a homework (as the OP CLEARLY indicated) it is important to ask what are they currently learning in order to properly frame the answer to the lesson. Basically, the most correct answer for industry might not (and often it is not) the most correct answer for what it is being taught.
#Janis Klein, what you are covering in class at the moment is very important. For example, if you are learning about sorting, the answer might be to implement some sort of sorting algorithm. When you sort a collection of numbers, the most negative and the most positive will be the head and tail values in your sorted collection. If you are learning about lists and collections, the answer might be to implement some sort of linked list where the numbers are inserted in natural order (no need to sort). Like in my previous example, once you insert all 100 values into this list, the head and tail values are the most positive and negative values.
However, if all you are learning is to do comparisons of values, you don't need but two variables (one for most positive and one for most negative) and all you will need to do is to compare incoming values and store them into the correct variable if needed. For example, the very first value will be both the most positive and most negative. The second incoming value will be either the most positive or most negative (assuming unique values are always received). From the third value on, the incoming value MIGHT be the most positive, the most negative, or simply neither; in which case, the incoming value is discarded. In the end, the most negative and most positive values will be the values stored in the respective variables.
Again, the scope of the answer MUST be framed based on what you are currently learning in class.

Trying to create a program that immitates a 6 sided dice using the Math class

I understand I have to use the random method but thats where my understanding ends
The Random class has a nextInt(int) method that makes it easy to select a value:
Random random = new Random(); // ... or possibly reuse an existing Random
int side = random.nextInt(6); // resulting side is in 0...5
In many other languages, there is only a method to obtain an evenly-distributed number between 0 and 1. In those cases, multiplying this value by the size of the range will give you an evenly distributed number in the desired range, and then you simply add an offset to shift the result into the range in question. This is the same principle by which the internals of nextInt() operates.

java random number generator - lottery

My code will seem amateurish as I am a software engineering student in 2nd year.
I created a lottery number generator and have noticed peculiar but consistent results. My program attempts to match the previous lottery numbers for the Euro Millions draw. I track the number of attempts it takes and i also track the number of times I match 3, 4, 5 and 6 numbers.
The attempts range between 1 million and 422 million. i.e. I would run the program 10 times and I would achieve a range, I would also track the length of time each run takes.
I account for a number of things like preventing a random number from being used more than once and this check is done against a HashMap of the possible lottery numbers. If I find the random number within the hashmap I add the number to an arraylist and then remove the number from the hashmap.
My questions surrounds the results.
In all attempts to match the lottery numbers my chance of getting 3 numbers was 3.13% on average. For 4 numbers it dropped to 0.28%, 5 numbers 0.00012% and 6 numbers 0.00022%.
Understandably The chance of winning as the number of lottery numbers increase is going to decrease however whether I had 1 million or 100 million attempts the ratio was the same or extremely close.
If you are interested my smallest number of attempts was 1,088,157, it took approximately 6 seconds or 6612ms.
Largest number of attempts was 422,036,905 and it took 26mins or 1589867ms.
Since I am using the Java Random library I am merely looking for some clarity on this. Or should I simply put it down to probability?
My code is an unnecessary 225 lines, if you would like to see a particular part or prefer to see the whole thing then please request this. Here is a sample below of the random number generation for the first 5 numbers.
//stores all possible lottery numbers
public static HashMap<Integer,Integer> randRange = new HashMap<Integer,Integer>();
//stores bonus ball numbers
public static HashMap<Integer,Integer> boRange = new HashMap<Integer,Integer>();
//stores lottery number output
public static ArrayList<Integer> lotNum = new ArrayList<Integer>();
//stores bonus ball output
public static ArrayList<Integer> boNum = new ArrayList<Integer>();
public static void randomInt(){
Random rand = new Random();
//generate a random number
int RandInt = rand.nextInt(51);
int boInt = rand.nextInt(12);
//loop used to get unique random number
int count=0;
while(count!=5){
//check if random number exists
if(randRange.get(RandInt)!=null)
{
//finalise random number
RandInt=randRange.get(RandInt);
//add to ArrayList
lotNum.add(RandInt);
//remove number
//ensures next random number is unique
randRange.remove(RandInt);
count++;
}
else
{
//get a new random number
//and start process again
RandInt = rand.nextInt(51);
}
}
}
EDIT:
First of all sorry I couldn't upvote as I have less than 15 reputation. All answers were helpful including comments.
Thanks to the suggestions by all members I improved my program and discovered unsurprisingly a fault in my code. #digitaljoel you were correct in the probability of matching 5 and 6 numbers. I set up the calculation incorrectly, e.g. for the numbers 11,20 30,35,45,2,3 for the euromillions draw to match 3 was 0.7%, 4 was .05%, 5 was .00273% and 6 was .000076%.
Thanks to #maybewecouldstealavan I changed my shuffling method to simply populate an ArrayList and shuffle the list, get the first five numbers and do the same for the bonus balls. The benefit was in the number of checks per second increasing from 150 - 200 thousand checks per second to 250-700 thousand checks per second.
Thanks to #trutheality as in some cases if i checked 1000 or 1,000,000 matches the variation was similar or minute.
#LeviX Appreciate again the calculation for the possible combinations. I used this within the program and found that it took more than the total number of combinations to win the lottery. Most likely I am producing duplicate random numbers. From this i will probably create all possible combinations and randomly select each combination until the program finds a match.
In all attempts to match the lottery numbers my chance of getting 3 numbers was 3.13% on average. For 4 numbers it dropped to 0.28%, 5 numbers 0.00012% and 6 numbers 0.00022%.
Understandably The chance of winning as the number of lottery numbers increase is going to decrease however whether I had 1 million or 100 million attempts the ratio was the same or extremely close.
That is actually not surprising at all. What you end up doing here is estimating the probability of guessing 3,4,5, or 6 numbers correctly. Having more samples will only make the variations in your estimates smaller, but even with "as little" as 1 million samples, your estimate is expected to be close to the exact probability (which you could calculate by doing some math).
Do you mean that you expect the proportion of times that you win to be more "random"? If that's what you're getting at, then #truthreality is quite correct. For further reading you might look at the law of large numbers and the central limit theorem.
If you're asking if your method of shuffling is correct, it is though it is inefficient. You're generating more random numbers than necessary, since you're just checking for dupes when they occur, and you're not creating a new random number after you pick a ball, so you're requiring a minimum of one HashMap.get(int) per pick.
I might use one of the following methods instead:
1) Create an ArrayList containing all the ball values. For each drawing, use Collections.shuffle(yourArrList, rand) to shuffle a clone of it them, then just use the first 5 balls from the list.
2) Again, create an Array or ArrayList of ball values. Then implement a portion of the shuffle operation yourself: Choose from smaller and smaller subsets of the possibilities and swap in the element that no longer fits into the place of the element that was just chosen. The advantage is that you don't need to shuffle the entire array. Here's my quick and dirty implementation:
public static int[] choose(int[] array, int count, Random rand) {
int[] ar = array.clone();
int[] out = new int[count];
int max = ar.length;
for (int i = 0; i<count; i++) {
int r = rand.nextInt(max);
//max is decremented,
//the selected value is copied out then overwritten
//by the last value, which would no longer be accessible
max--;
out[i]=ar[r];
ar[r]=ar[max];
}
return out;
}
There's probably room for improvement, especially if order doesn't matter.
From my understanding there are two different parts to the Euro Millions. The 5 balls and then the 2 bonus balls. You can check the math of your program by figuring out the exact probabilities of winning. I'm sure you can google it, but it's easy to calculate.
Probability of getting 5 balls out of 50 (order doesn't matter)
P(A) = 50!/5!(50-5)! = 2,118,760
Probability of getting 2 balls out of 11 (order doesn't matter)
P(B) 11!/2!(11-2)! = 55
The two events are independent so multiply them together.
P(A) * P(B) = P(A&B)
2,118,760 * 55 = 116,531,800
Therefore the chances of winning the lottery is:
1 in 116,531,800

probability and programming simulation

I'm having some trouble understanding the following result.
I want to know if the following code is actually correct. It stumps me - but that could be due to me misunderstanding the probability involved.
The code should speak for itself, but to clarify the 'real world' simulation represents 2 people flipping a coin. When you lose you pay 1 dollar, when you win you win a dollar. An even sum game!
private static Random rnd = new Random();
public static void main(String[] args) {
int i=0;
for (int x = 0; x<1000000; x++) {
if (rnd.nextBoolean()) i+=1;
else i-=1;
}
System.out.println(i);
}
When I run this however I get huge swings! Whilst I would expect a large sample like this to converge to 0, I'm seeing +-4000
Not only that but increasing the sample size seems to only make the swings higher.
Am I misusing the random function ? :P
I think you're good. The thing to look at is the ratio of the swing to your sample.
4000 out of 1000000 for example is 0.4%
If you increase the sample size, you should expect that ratio to go down.
The results of your experiment should follow a binomial distribution. If the
number of trials is N, and the probability of success p=1/2, then the
number of successes N_success (for large enough N) should have a mean of approximately Np,
and standard deviation sqrt(N*p*(1-p)).
You're actually tracking K = (N_success - N_fail). So N_success = N/2 + K/2.
With 1,000,000 trials and K=4000, we get N_success = 502000. The expected
value is 500000, with standard deviation sqrt(250000) = 500. The difference
between the observed and expected values of N_success is 2000, or about 4 sigma.
That's significant enough to question whether the random number generator is
biased. On the other hand, if you're running this test thousands of times,
you'd expect a few outliers of this magnitude, and you seem to be seeing both
positive and negative values, so in the long run maybe things are OK after all.
You are simulating a one-dimensional random walk. Basically, imagine yourself standing on a line of integers. You begin at point i=0. With equal probability you take a step to the right or the left.
The random walk has a few cool properties and you've touched on my favourite:
Starting at point i=0, as N gets larger, the probability that you will return to that point approaches 1. As you point out - a zero sum game.
However, the expected time it will take you to return there tends to infinity. As you notice, you get some very large swings.
Since the average value should be 0 and the variance of N moves is N, then you would expect 95% of your simulations to end in the region: (- 1.96, 1.96)*N^(0.5).

How to multiply two big big numbers

You are given a list of n numbers L=<a_1, a_2,...a_n>. Each of them is
either 0 or of the form +/- 2k, 0 <= k <= 30. Describe and implement an
algorithm that returns the largest product of a CONTINUOUS SUBLIST
p=a_i*a_i+1*...*a_j, 1 <= i <= j <= n.
For example, for the input <8 0 -4 -2 0 1> it should return 8 (either 8
or (-4)*(-2)).
You can use any standard programming language and can assume that
the list is given in any standard data structure, e.g. int[],
vector<int>, List<Integer>, etc.
What is the computational complexity of your algorithm?
In my first answer I addressed the OP's problem in "multiplying two big big numbers". As it turns out, this wish is only a small part of a much bigger problem which I'm going to address now:
"I still haven't arrived at the final skeleton of my algorithm I wonder if you could help me with this."
(See the question for the problem description)
All I'm going to do is explain the approach Amnon proposed in little more detail, so all the credit should go to him.
You have to find the largest product of a continuous sublist from a list of integers which are powers of 2. The idea is to:
Compute the product of every continuous sublist.
Return the biggest of all these products.
You can represent a sublist by its start and end index. For start=0 there are n-1 possible values for end, namely 0..n-1. This generates all sublists that start at index 0. In the next iteration, You increment start by 1 and repeat the process (this time, there are n-2 possible values for end). This way You generate all possible sublists.
Now, for each of these sublists, You have to compute the product of its elements - that is come up with a method computeProduct(List wholeList, int startIndex, int endIndex). You can either use the built in BigInteger class (which should be able to handle the input provided by Your assignment) to save You from further trouble or try to implement a more efficient way of multiplication as described by others. (I would start with the simpler approach since it's easier to see if Your algorithm works correctly and first then try to optimize it.)
Now that You're able to iterate over all sublists and compute the product of their elements, determining the sublist with the maximum product should be the easiest part.
If it's still to hard for You to make the connections between two steps, let us know - but please also provide us with a draft of Your code as You work on the problem so that we don't end up incrementally constructing the solution and You copy&pasting it.
edit: Algorithm skeleton
public BigInteger listingSublist(BigInteger[] biArray)
{
int start = 0;
int end = biArray.length-1;
BigInteger maximum;
for (int i = start; i <= end; i++)
{
for (int j = i; j <= end; j++)
{
//insert logic to determine the maximum product.
computeProduct(biArray, i, j);
}
}
return maximum;
}
public BigInteger computeProduct(BigInteger[] wholeList, int startIndex,
int endIndex)
{
//insert logic here to return
//wholeList[startIndex].multiply(wholeList[startIndex+1]).mul...(
// wholeList[endIndex]);
}
Since k <= 30, any integer i = 2k will fit into a Java int. However the product of such two integers might not necessarily fit into a Java int since 2k * 2k = 22*k <= 260 which fill into a Java long. This should answer Your question regarding the "(multiplication of) two numbers...".
In case that You might want to multiply more than two numbers, which is implied by Your assignment saying "...largest product of a CONTINUOUS SUBLIST..." (a sublist's length could be > 2), have a look at Java's BigInteger class.
Actually, the most efficient way of multiplication is doing addition instead. In this special case all you have is numbers that are powers of two, and you can get the product of a sublist by simply adding the expontents together (and counting the negative numbers in your product, and making it a negative number in case of odd negatives).
Of course, to store the result you may need the BigInteger, if you run out of bits. Or depending on how the output should look like, just say (+/-)2^N, where N is the sum of the exponents.
Parsing the input could be a matter of switch-case, since you only have 30 numbers to take care of. Plus the negatives.
That's the boring part. The interesting part is how you get the sublist that produces the largest number. You can take the dumb approach, by checking every single variation, but that would be an O(N^2) algorithm in the worst case (IIRC). Which is really not very good for longer inputs.
What can you do? I'd probably start from the largest non-negative number in the list as a sublist, and grow the sublist to get as many non-negative numbers in each direction as I can. Then, having all the positives in reach, proceed with pairs of negatives on both sides, eg. only grow if you can grow on both sides of the list. If you cannot grow in both directions, try one direction with two (four, six, etc. so even) consecutive negative numbers. If you cannot grow even in this way, stop.
Well, I don't know if this alogrithm even works, but if it (or something similar) does, its an O(N) algorithm, which means great performance. Lets try it out! :-)
Hmmm.. since they're all powers of 2, you can just add the exponent instead of multiplying the numbers (equivalent to taking the logarithm of the product). For example, 2^3 * 2^7 is 2^(7+3)=2^10.
I'll leave handling the sign as an exercise to the reader.
Regarding the sublist problem, there are less than n^2 pairs of (begin,end) indices. You can check them all, or try a dynamic programming solution.
EDIT: I adjusted the algorithm outline to match the actual pseudo code and put the complexity analysis directly into the answer:
Outline of algorithm
Go seqentially over the sequence and store value and first/last index of the product (positive) since the last 0. Do the same for another product (negative) which only consists of the numbers since the first sign change of the sequence. If you hit a negative sequence element swap the two products (positive and negative) along with the associagted starting indices. Whenever the positive product hits a new maximum store it and the associated start and end indices. After going over the whole sequence the result is stored in the maximum variables.
To avoid overflow calculate in binary logarithms and an additional sign.
Pseudo code
maxProduct = 0
maxProductStartIndex = -1
maxProductEndIndex = -1
sequence.push_front( 0 ) // reuses variable intitialization of the case n == 0
for every index of sequence
n = sequence[index]
if n == 0
posProduct = 0
negProduct = 0
posProductStartIndex = index+1
negProductStartIndex = -1
else
if n < 0
swap( posProduct, negProduct )
swap( posProductStartIndex, negProductStartIndex )
if -1 == posProductStartIndex // start second sequence on sign change
posProductStartIndex = index
end if
n = -n;
end if
logN = log2(n) // as indicated all arithmetic is done on the logarithms
posProduct += logN
if -1 < negProductStartIndex // start the second product as soon as the sign changes first
negProduct += logN
end if
if maxProduct < posProduct // update current best solution
maxProduct = posProduct
maxProductStartIndex = posProductStartIndex
maxProductEndIndex = index
end if
end if
end for
// output solution
print "The maximum product is " 2^maxProduct "."
print "It is reached by multiplying the numbers from sequence index "
print maxProductStartIndex " to sequence index " maxProductEndIndex
Complexity
The algorithm uses a single loop over the sequence so its O(n) times the complexity of the loop body. The most complicated operation of the body is log2. Ergo its O(n) times the complexity of log2. The log2 of a number of bounded size is O(1) so the resulting complexity is O(n) aka linear.
I'd like to combine Amnon's observation about multiplying powers of 2 with one of mine concerning sublists.
Lists are terminated hard by 0's. We can break the problem down into finding the biggest product in each sub-list, and then the maximum of that. (Others have mentioned this).
This is my 3rd revision of this writeup. But 3's the charm...
Approach
Given a list of non-0 numbers, (this is what took a lot of thinking) there are 3 sub-cases:
The list contains an even number of negative numbers (possibly 0). This is the trivial case, the optimum result is the product of all numbers, guaranteed to be positive.
The list contains an odd number of negative numbers, so the product of all numbers would be negative. To change the sign, it becomes necessary to sacrifice a subsequence containing a negative number. Two sub-cases:
a. sacrifice numbers from the left up to and including the leftmost negative; or
b. sacrifice numbers from the right up to and including the rightmost negative.
In either case, return the product of the remaining numbers. Having sacrificed exactly one negative number, the result is certain to be positive. Pick the winner of (a) and (b).
Implementation
The input needs to be split into subsequences delimited by 0. The list can be processed in place if a driver method is built to loop through it and pick out the beginnings and ends of non-0 sequences.
Doing the math in longs would only double the possible range. Converting to log2 makes arithmetic with large products easier. It prevents program failure on large sequences of large numbers. It would alternatively be possible to do all math in Bignums, but that would probably perform poorly.
Finally, the end result, still a log2 number, needs to be converted into printable form. Bignum comes in handy there. There's new BigInteger("2").pow(log); which will raise 2 to the power of log.
Complexity
This algorithm works sequentially through the sub-lists, only processing each one once. Within each sub-list, there's the annoying work of converting the input to log2 and the result back, but the effort is linear in the size of the list. In the worst case, the sum of much of the list is computed twice, but that's also linear complexity.
See this code. Here I implement exact factorial of a huge large number. I am just using integer array to make big numbers. Download the code from Planet Source Code.

Categories

Resources