I am an absolute beginner to learning programming and I was given this assignment:
Birthday problem. Suppose that people enter a room one at a time. How people must enter until two share a birthday? Counterintuitively, after 23 people enter the room, there is approximately a 50–50 chance that two share a birthday. This phenomenon is known as the birthday problem or birthday paradox.
Write a program Birthday.java that takes two integer command-line arguments n and trials and performs the following experiment, trials times:
Choose a birthday for the next person, uniformly at random between 0 and n−1.
Have that person enter the room.
If that person shares a birthday with someone else in the room, stop; otherwise repeat.
In each experiment, count the number of people that enter the room. Print a table that summarizes the results (the count i, the number of times that exactly i people enter the room, and the fraction of times that i or fewer people enter the room) for each possible value of i from 1 until the fraction reaches (or exceeds) 50%.
For more information on the assignment
However, my code won't print. I would really appreciate if someone could help me find the problem to my assignment.
public class Birthday {
public static void main(String[] args) {
int n = Integer.parseInt(args[0]); //number of days
int trials = Integer.parseInt(args[1]);
boolean[] birthdays = new boolean[n];
int[] times = new int[n + 2]; //number of times i people entered the room
int r;
for (int t = 1; t <= trials; t++) {
for (int k = 0; k < n; k++) { //reset birthday
birthdays[k] = false;
}
for (int i = 1; i <= n; i++) { //number of times
r = (int) (Math.random() * (n - 1)); //random birthday
if (birthdays[r] = false) {
birthdays[r] = true;
continue;
}
else if (birthdays[r] = true) {
times[i]++; //number of times i people entered the room + 1
break;
}
}
}
int j = 1;
while ((double) times[j] / trials <= 0.5) {
System.out.print(j + "\t" + times[j] + "\t" + ((double) times[j] / trials));
j++;
System.out.println("");
}
}
}
I can spot two errors from your code
As Scary Wombat pointed out, you are miss double equal sign inside of your if statement.
The assignment is asking you to calculate "fraction of times that i or fewer people enter the room", meaning you need to do a summation for the first i indices and divided by trials.
For example, among 1 million trials, the fraction in which first duplicate birthday happens when 4th person enters is
(times[0] + times[1] + times[2] + times[3])/ 1000000
Here is what I got:
1 0 0.0
2 2810 0.00281
3 5428 0.008238
4 8175 0.016413
As you can see the fraction is calculated by adding the first three elements together and then divided by 1000000 (2810 + 5428 + 8175 = 16413) / 1000000 = 0.016413
The way you are calculating the fraction ((double) times[j] / trials) is not correct.
You are not adding the previous counts as shown in the example. To do so, you can create a new variable to store the sums of previous counts. and use it as your while loop condition. For instance, see below..
csum += times[j]; // this adds the previous counts into a cumulative sum.
This cumulative sum is supposed to be the one u use to divide by trials to get your probability. Cheers!
Related
Given that N is a random number (range 1 to 1000). We need to guess the N and for each guess, one of the following feedbacks may be given:
The guess is correct;
The guess is too large, so you should guess a smaller number;
The guess is too small, so you should guess a larger number.
In case 3, the value of N will increase by P, where P is another random number(range 1 to 200).
If the initial value of N=800 and P=150. You guess in the following sequence:
Example
How do you code the following especially when it involves two number (N and P). I was thinking of using Binary Search but the it would be a problem if we do not know the value of P.
This is my code as of now :
myGuess=0;
checkCode=0;
int lower = 1, upper = 999;
myGuess = (lower+upper)/2;
do{
if (checkCode == 2) {
upper = myGuess - 1;
}
else if (checkCode == 3){
lower = myGuess + 1;
upper += ran.nextInt(200); //Need to guess the P value
}
myGuess = (lower+upper)/2;
}while(checkCode!=1);
The first step is to obtain a working guessing system. This code provides a rough guide to a binary search approach. The second step would the be to analyze how to improve efficiency. (note: can restore some of the S.O.P() to see progress)
private static int doGuess()
{
int lowerBound = 1;
int upperBound = 1000;
int numberToGuess = ThreadLocalRandom.current().nextInt(upperBound) + 1;
int guess = 0;
int steps = 0;
int increases = 0;
while (guess != numberToGuess) {
++steps;
guess = (lowerBound + upperBound) / 2;
// System.out.printf("[%5d] Guessing %d (is: %d)%n",
// steps,
// guess,
// numberToGuess);
if (guess == numberToGuess) {
System.out.printf("Guessed %d in %d steps (%d increases)%n",
numberToGuess,
steps,
increases);
continue;
}
else if (guess > numberToGuess) {
// System.out.println("Guess is too high!");
// adjust upper bound to be guess
upperBound = guess;
}
else {
// System.out.println("Guess is too low; changing number");
numberToGuess += ThreadLocalRandom.current().nextInt(200) + 1;
// adjust lower bound to this guess
lowerBound = guess;
// the number moved, so adjust upper bound by max range
upperBound += 200;
// track increases
++increases;
}
}
return steps;
}
public static void main(String[] args)
{
List<Integer> steps = new ArrayList<>();
int iterations = 10;
for (int i = 0; i < iterations; ++i) {
steps.add(doGuess());
}
IntSummaryStatistics stats =
steps.stream().collect(IntSummaryStatistics::new,
IntSummaryStatistics::accept,
IntSummaryStatistics::combine);
System.out.println(stats);
}
Output:
Guessed 8838 in 145 steps (83 increases)
Guessed 6301 in 106 steps (59 increases)
Guessed 3239 in 58 steps (30 increases)
Guessed 5785 in 109 steps (58 increases)
Guessed 2547 in 56 steps (27 increases)
Guessed 16071 in 300 steps (164 increases)
Guessed 3847 in 54 steps (31 increases)
Guessed 3125 in 42 steps (24 increases)
Guessed 6708 in 93 steps (57 increases)
Guessed 7433 in 143 steps (74 increases)
IntSummaryStatistics{count=10, sum=1106, min=42, average=110.600000, max=300}
[Note: based upon quick simulations, the average across multiple runs is about 115, so efficiency improvements should reduce on average from 115 steps]
[Note: the amount of change in the code is different with each guess that is too low; a comment by the OP might suggest the increase is randomly chosen once, in which case the increase in the number to guess in the above code would need to change]
Edit:
Logically if guessing low moves the the number one is to guess, then using some sort of bias towards picking higher would seem to be logical. As Holger has suggest in the various comments, there are some ways to make adjustments.
I had attempted some basic adjustments prior to seeing Holger's suggestion; I then also attempted to implement his algorithm. However, I have not found the adjustments to make a marked improvement (and some are worse).
Using 100,000 runs, the standard binary search averaged 127.7 steps (note: up slightly from my earlier estimate based upon a lower run count). Assuming I implemented Holger's algorithm correctly, at 100,000 the average was 126.6 steps.
As I lack the math skills (and unfortunately time at the moment) to investigate further, it seems that simple modifications do not seem to radically change the efficiency of the algorithm on average. I did not investigate worse cases. It would be interesting to ask the question over on the Math StackExchange to see if they could provide any definite input. I did do a quick Google search, but did not have time to read the academic papers that might give some improvement (again, with unknown trade-offs in speed and algorithmic complexity).
It is, of course, possible I did not implement Holgen's suggestion properly. Here is the code I used (replacing the change in the guess calculation if too low) based straight from the comment:
if (tryHolgen) {
double risc = 200.0/(upperBound-lowerBound);
if (risc <= 1) {
guess = (upperBound + lowerBound) /2;
}
else {
guess = upperBound -
Math.max((int)((upperBound - lowerBound)/risc/2),1);
}
else {
guess = (lowerBound + upperBound) / 2;
}
I am curious if others have a better implementation than the straight binary search.
It is interesting, though, that a 1..1000 range with a standard binary search would take 8 steps on average with O(log n) complexity. By allowing the guess to change, it moves the average by about 120 steps.
I reworked my solution once I understood what you were trying to do. This will give you some statistics. The current solution incorporates a random number between 0 and 13 for each guess, as well as adding the lower and upper bound together and divide them by 2. Why 13? It seems like it's a sweet spot for this exact task.
public static void main(String args[]) throws IOException {
int numTests = 1000000;
long averageTries = 0;
int maxAttempts = 0;
int minAttempts = Integer.MAX_VALUE;
for (int i = 0; i < numTests; i++) {
int numAttempts = 0;
int answer = (int) (Math.random() * 1000) + 1;
int lower = 1;
int upper = 1000;
int myGuess;
do {
myGuess = (int) (((lower + upper) / 2) + (Math.random() * 14));
numAttempts++;
if (myGuess > answer) {
upper = myGuess;
} else if (myGuess < answer) {
lower = myGuess;
upper += (lower + upper) / 2;
answer += (int) (Math.random() * 200) + 1;
}
} while (myGuess != answer);
averageTries += numAttempts;
if (numAttempts > maxAttempts) {
maxAttempts = numAttempts;
}
if (numAttempts < minAttempts) {
minAttempts = numAttempts;
}
}
System.out.println("Average attempts (of " + numTests + " tests): " + (averageTries / numTests));
System.out.println("Most attempts in one run: " + maxAttempts);
System.out.println("Least attempts in one run: " + minAttempts);
}
Output:
Average attempts (of 1000000 tests): 266
Most attempts in one run: 72228
Least attempts in one run: 1
You can try to do something similar to binary search. Just consider that binary search requires the input to be sorted. If the input is not sorted you have to sort it yourself.
Rather than guessing a random number, just guess the one exactly in the middle of the partition. However compared with binary search which halves each time, in this case it's a moving target, so the bounds of the search need to be adjusted for that.
So, I am working on this code for my AP Computer Science class, and I ran into a problem.
First, here is my code:
//loop counters
int counterOne = 0;
int counterElse = 0;
int loop = 1;
int iNum = 1000;
//create file
PrintWriter outFile = new PrintWriter(new File("newFile.txt"));
for (int counter = 1; counter <= iNum; counter++)
{
while (loop >= 1)
{
Random rand = new Random();
int iRand = rand.nextInt(5)+1;
if (iRand != 1)
{
counterElse++;
loop++;
}//end of if of if-else
else
{
counterOne++;
loop = 0;
}//end of else of if-else
}//end of while loop
int tries = counterElse+counterOne;
//int average = (tries + prevTriesSum) / counter
System.out.println("It took " + tries + " try/tries to win!");
//outFile.println("It tool an average of " + average + " tries to win.");
}//end of for loop
How do I calculate the average of the trials? As you can see from the end of my code, I commented out a line that I would want to calculate the average. This is because I don't know how to calculate prevTriesSum, which represents the sum of all of the other trials. Here is an example: Assume the loop runs six times, and with the first run, it takes 3 tries, 5 on the second run, 7 on the third, 11 on the fourth, 2 on the fifth, and 4 on the sixth (the most recent one. now tries = 4).
I would want prevTriesSum to equal 3 + 5 + 7 + 11 + 2 + 4.
How do I get the program to calculate that?
Your average is computed in integer arithmetic which means any fractional part is discarded. Consider using a floating point type for the average, and prefix the right hand side of the assignment with 1.0 * to force the calculation to occur in floating point.
You must not reinitialise the random generator in the loop, else you ruin its statistical properties. Do it once before you enter the loop.
Before the while loop, add
int prevTriesSum = 0;
Replace your commented int average = line with
prevTriesSum += tries;
And after the for loop add
double average = (prevTriesSum + 0.0) / counter;
outFile.println("It tool an average of " + average + " tries to win.");
As for the random number generator, Bathsheba is correct. You must move that above the for loop. Just move the declaration.
You'll also need to change your for loop slightly. As it stands, it will equal 1001 when the for loop terminates. Change it as follows:
for (int counter = 0; counter < iNum; counter++)
This will ensure that your average calculation is correct.
Firstly, I'm taking AP Computer Science this year, and this question is related to an exercise we were assigned in class. I have written the code, and verified that it meets the requirements to my knowledge, so this is not a topic searching for homework answers.
What I'm looking for is to see if there's a much simpler way to do this, or if there's anything I could improve on in writing my code. Any tips would be greatly appreciated, specific questions asked below the code.
The exercise is as follows: Write a program called ProcessingNumbers that does:
Accepts a user input as a string of numbers
Prints the smallest and largest of all the numbers supplied by the user
Print the sum of all the even numbers the user typed, along with the largest even number typed.
Here is the code:
import java.util.*;
public class ProcessingNumbers {
public static void main(String[] args) {
// Initialize variables and objects
Scanner sc = new Scanner(System.in);
ArrayList<Integer> al = new ArrayList();
int sumOfEven = 0;
// Initial input
System.out.print("Please input 10 integers, separated by spaces.");
// Stores 10 values from the scanner in the ArrayList
for(int i = 0; i < 10; i++) {
al.add(sc.nextInt());
}
// Sorts in ascending order
Collections.sort(al);
// Smallest and largest values section
int smallest = al.get(0);
int largest = al.get(al.size() - 1);
System.out.println("Your smallest value is " + smallest + " and your largest value is " + largest);
// Sum of Even numbers
int arrayLength = al.size();
for (int i = 0; i < al.size(); i++) {
if (al.get(i) % 2 == 0) {
sumOfEven += al.get(i);
}
}
System.out.println("The sum of all even numbers is " + sumOfEven);
// Last section, greatest even number
if (al.get(arrayLength - 1) % 2 == 0) {
System.out.println("The greatest even number typed is " + al.get(arrayLength - 1));
} else {
System.out.println("The greatest even number typed is " + al.get(arrayLength - 2));
}
sc.close();
}
}
Here are specific questions I'd like answered, if possible:
Did I overthink this? Was there a much simpler, more streamlined way to solve the problem?
Was the use of an ArrayList mostly necessary? We haven't learned about them yet, I did get approval from my teacher to use them though.
How could I possibly code it so that there is no 10 integer limit?
This is my first time on Stackoverflow in quite some time, so let me know if anything's out of order.
Any advice is appreciated. Thanks!
Usage of the ArrayList wasn't necessary, however it does make it much simpler due to Collections.sort().
To remove the 10 integer limit you can ask the user how many numbers they want to enter:
int numbersToEnter = sc.nextInt();
for(int i = 0; i < numbersToEnter; i++) {
al.add(sc.nextInt());
}
Another note is that your last if-else to get the highest even integer doesn't work, you want to use a for loop, something like this:
for (int i = al.size() - 1; i >= 0; i--) {
if (al.get(i) % 2 == 0) {
System.out.println("The greatest even number typed is " + al.get(i));
break;
}
I wouldn't say so. Your code is pretty straightforward and simple. You could break it up into separate methods to make it cleaner and more organized, though that isn't necessary unless you have sections of code that have to be run repeatedly or if you have long sections of code cluttering up your main method. You also could have just used al.size() instead of creating arrayLength.
It wasn't entirely necessary, though it is convenient. Now, regarding your next question, you definitely do want to use an ArrayList rather than a regular array if you want it to have a variable size, since arrays are created with a fixed size which can't be changed.
Here's an example:
int number;
System.out.print("Please input some integers, separated by spaces, followed by -1.");
number = sc.nextInt();
while (number != -1) {
al.add(number);
number = sc.nextInt();
}
Here is a solution that:
Doesn't use Scanner (it's a heavyweight when all you need is a line of text)
Doesn't have a strict limit to the number of numbers
Doesn't need to ask how many numbers
Doesn't waste space/time on a List
Handles the case when no numbers are entered
Handles the case when no even numbers are entered
Fails with NumberFormatException if non-integer is entered
Moved actual logic to separate method, so it can be mass tested
public static void main(String[] args) throws Exception {
System.out.println("Enter numbers, separated by spaces:");
processNumbers(new BufferedReader(new InputStreamReader(System.in)).readLine());
}
public static void processNumbers(String numbers) {
int min = 0, max = 0, sumOfEven = 0, maxEven = 1, count = 0;
if (! numbers.trim().isEmpty())
for (String value : numbers.trim().split("\\s+")) {
int number = Integer.parseInt(value);
if (count++ == 0)
min = max = number;
else if (number < min)
min = number;
else if (number > max)
max = number;
if ((number & 1) == 0) {
sumOfEven += number;
if (maxEven == 1 || number > maxEven)
maxEven = number;
}
}
if (count == 0)
System.out.println("No numbers entered");
else {
System.out.println("Smallest number: " + min);
System.out.println("Largest number: " + max);
if (maxEven == 1)
System.out.println("No even numbers entered");
else {
System.out.println("Sum of even numbers: " + sumOfEven);
System.out.println("Largest even number: " + maxEven);
}
}
}
Tests
Enter numbers, separated by spaces:
1 2 3 4 5 6 7 8 9 9
Smallest number: 1
Largest number: 9
Sum of even numbers: 20
Largest even number: 8
Enter numbers, separated by spaces:
1 3 5 7 9
Smallest number: 1
Largest number: 9
No even numbers entered
Enter numbers, separated by spaces:
-9 -8 -7 -6 -5 -4
Smallest number: -9
Largest number: -4
Sum of even numbers: -18
Largest even number: -4
Enter numbers, separated by spaces:
No numbers entered
I'm currently doing a course in computer science which is technically for beginners, but I feel all the assignments they are giving me are more complicated than I can handle.
This assignment asks me to make a coin toss simulation. Three people play the game and each of them has specific requirements to win:
One wins if there are 2 results head and the total number of tosses
is even
One wins if there are 2 results tails and the total number of tosses is even
One wins if there are 2 results tails OR heads and the total number of tosses is odd
What I should do is run an experiment 300 times. Each time I should determine who of the three won and how many times. And I'm really stuck. I barely have any code but I do have an very basic idea of what the code should be like, but I can't put it into Java language.
For my assignment, I need to display the binary sequence that caused a person to win.
My idea:
Initialize a counter (1, 2, 3) for every person so that I can keep track of how many times they win
Initialize a head count and a tails count to keep track of the randomly generated sequence
Use a for loop for practically the whole experiment. There should be an outer loop that defines the experiment should be run 300 times and the inner loop should contain the if statements that check who has won. There should be a counter in every if statement, so that I can update it for every person. And I need a System.out.println(); to print every single result of the experiment.
Print the final outcome of the experiment, using the previously determined counters
EDIT:
I've tried to change what everyone said and it does look better now, thanks! But it's still not doing what it's supposed to do and I wonder why. I run the code and I only get one output; not the 300 times I want it to run. Furthermore, the counters at the end don't hold the information about who has won, they reset every single time. And sometimes two people win, while that should not be possible. Could anyone clarify this?
EDIT:
This is another update of the code. I believe it does run 300 times now! A problem now is the output. Sometimes it says; 1 Bernie wins, while you obviously need at least 2 results for Bernie to win. Also, it says 1 Penny wins, while that also shouldn't be possible. Did I mess something up in my if statements?
import java.util.Random;
public class Assignment3e
{
public static void main(String[] args)
{
int counter1 = 0;
int counter2 = 0;
int counter3 = 0;
Random coin = new Random();
for(int i = 0; i <= 300; i++){
int headCount = 0;
int tailsCount = 0;
for(int coinToss = 0; coinToss <= 3; coinToss++){
int random = (int) (Math.random() * 6) + 1;
String binary = Integer.toBinaryString(random);
boolean result = coin.nextBoolean();
if(result){
headCount++;
}
else{
tailsCount++;
}
if(headCount == 2 && binary.length() % 2 ==0){
//Amy wins
counter1 = counter1 + 1;
System.out.println(binary + " Amy wins.");
}
else if(tailsCount == 2 && binary.length() % 2 == 0){
//Penny wins
counter2 = counter2 + 1;
System.out.println(binary + " Penny wins.");
}
else if(headCount == 2 || tailsCount == 2 && binary.length() % 2 != 0){
//Bernie wins
counter3 = counter3 + 1;
System.out.println(binary + " Bernie wins.");
}
}
}
System.out.println("Amy wins " + counter1 + " times.");
System.out.println("Penny wins " + counter2 + " times.");
System.out.println("Bernie wins " + counter3 + " times.");
}
}
You almost got it right.
This part is not relevant anymore since OP add a requirement in comments.
Your second for loop only need to run a maximum of 3 times as there will be at least 2 heads or 2 tails, not 10.
Edit: you can do it with a maximun of 2 tosses: if there is 1 head and 1 tail, the winner is the 3rd player (Bernie)
Now, on each iteration, you can draw a random decimal number, between 0 and 1 and assume if it's over 0.5 it's a head so you increment the headCount, else you increment the tailCount. Then you can perform the test on the counters (and the number of tosses).
It's easier than using a binary String.
Edit:
To answer your comment:
Look where you initialized the headCountand tailCount. Remember that once one has won, those counters must be reset.
As it's homework, I won't post code :)
Edit:
OP jsut add a comment stating he need to print the sequence that lead to the result of each game.
We assume a binary 1 is a head, and a 0 is a tail. You need to toss the coin 3 times to know the sequence if Bernie wins. So the integer value random which is converted in binary string only need to be made of 3 bits (1 bit = 1 toss).
random can only take values between 0 and 7.
As you get all values in one shot, you don't need the coinToss for loop anymore. All you need to do is to check if the beginning of the binary string matches any win pattern (11 for 2 heads, 00 for 2 tails, else Bernie wins)
So there are a couple of things I'm noticing here:
You don't update headCount or tailCount anywhere. This should be what you're using to keep track of the number of coin flips.
When you go back to reuse these in subsequent loops, be sure to zero them out again.
You're using a very wide range for your result, when a simple nextBoolean would be all that needs to suffice. You could use it as this in your loop:
boolean result = coin.nextBoolean(); // this renames dice to coin
if(result) {
headCount++;
} else {
tailCount++;
}
The total number of tosses is always the current iteration's current value (plus 1). So, in your case, you could simply replace sum with j, but you'd want to give it a more meaningful name, like coinTosses instead.
If you're using a Random() object anyways for the coin nextBoolean(), why not replace the int random = (int) (Math.random() * 6) + 1; with int random = coin.nextInt([range here])?
The birthday paradox says that the probability that two people in a room
will have the same birthday is more than half as long as the number of
people in the room (n), is more than 23. This property is not really a paradox,
but many people find it surprising. Design a C++ program that can
test this paradox by a series of experiments on randomly generated birthdays,
which test this paradox for n =5, 10, 15, 20, . . . , 100. You should run
at least 10 experiments for each value of n and it should output, for each
n, the number of experiments for that n, such that two people in that test
have the same birthday.
package birth;
import java.util.Random;
/* Question:
The birthday paradox says that the probability that two people in a room
will have the same birthday is more than half as long as the number of
people in the room (n), is more than 23. This property is not really a paradox,
but many people find it surprising. Design a C++ program that can
test this paradox by a series of experiments on randomly generated birthdays,
which test this paradox for n =5, 10, 15, 20, . . . , 100. You should run
at least 10 experiments for each value of n and it should output, for each
n, the number of experiments for that n, such that two people in that test
have the same birthday.
*/
public class birth {
public static final int YEAR = 365;
public static void main(String[] args)
{
int numOfPeople = 5;
int people = 5;
//DOB array
int[] birthday = new int[YEAR];
//Creates an array that represents 365 days
for (int i = 0; i < birthday.length; i++)
birthday[i] = i + 1;
//Random Number generator
Random randNum = new Random();
int iteration = 1;
//iterates around peopleBirthday array
while (numOfPeople <= 100)
{
System.out.println("Iteration: " + iteration);
System.out.println();
//Creates array to holds peoples birthday
int[] peopleBirthday = new int[numOfPeople];
//Assigns people DOB to people in the room
for (int i = 0; i < peopleBirthday.length; i++)
{
int day = randNum.nextInt(YEAR + 1);
peopleBirthday[i] = birthday[day];
}
for (int i = 0; i < peopleBirthday.length; i++)
{
//stores value for element before and after
int person1 = peopleBirthday[i];
int person2 = i + 1;
//Checks if people have same birthday
for (int j = person2; j < peopleBirthday.length; j++)
{
//Prints matching Birthday days
if (person1 == peopleBirthday[j])
{
System.out.println("P1: " + person1 + " P2: " + peopleBirthday[j]);
System.out.println("Match!!! \n");
}
}
}
//Increments the number of people in the room
numOfPeople += 5;
iteration++;
}
}
}
I am getting a error: java.lang.ArrayIndexOutOfBoundsException: 365 I can't figure out what is wrong with my code
It would be nice if you provided the exact line number where the exception was thrown (the information is in the error stack trace that you got), but it's very likely that the problem occurs here:
int day = randNum.nextInt(YEAR + 1); // 365 + 1 = 366
peopleBirthday[i] = birthday[day];
The documentation for Random.nextInt says:
Returns: the next pseudorandom, uniformly distributed int value between zero (inclusive) and bound (exclusive) from this random number generator's sequence.
In this case, you are calling Random.nextInt with a value of 366 (365 + 1), so that means that you are effectively reading some random number between 0 and 365. If you ever do get 365, that will make birthday[day] throw the out of bounds exception, as the maximum index of your array is 364, not 365.
You probably meant to read the random value this way instead:
int day = randNum.nextInt(YEAR); // 365 (exclusive)
Arrays in Java are zero based. If you create birthday with a length of 365, the indexes would be from 0 to 364.
You need to change this line from this:
int[] birthday = new int[YEAR];
To this:
int[] birthday = new int[YEAR+1];