I'm having a problem with average distance in this exercise. It should be close to the sqrt of N steps, but it's lower. Can you help me to find out where is my mistake?
2D random walk.
A two dimensional random walk simulates the behavior of a particle moving in a grid of points.
At each step, the random walker moves north, south, east, or west with probability 1/4,
independently of previous moves. Determine how far away (on average) the random walker is from the starting point after N steps.
(Theoretical answer: on the order of sqrt(N).)
public class RandomWalk{
public static void main(String[] args){
int N = Integer.parseInt(args[0]);
double nextStep = 0;
double averageDistance = 0;
int COUNT = 1000;
for (int j = 0; j < COUNT; j++){
int moveWest = 0;
int moveEast = 0;
int moveSouth = 0;
int moveNorth = 0;
double distance = 0;
for (int i = 0; i < N; i++){
nextStep = Math.random()*4;
if (nextStep <= 1) ++moveWest;
else if (nextStep <= 2) ++moveEast;
else if (nextStep <= 3) ++moveSouth;
else if (nextStep <= 4)++moveNorth;
}
moveEast = moveEast - moveWest;
moveNorth = moveNorth - moveSouth;
distance = Math.sqrt((moveEast * moveEast) + (moveNorth * moveNorth));
averageDistance += distance;
System.out.println("Walker is " + distance + "\t steps away of from the starting point");
//System.out.println("Sqrt of N is " + Math.sqrt(N));
}
System.out.println("Average distance is " + averageDistance/COUNT + " steps away of from the starting point");
}
}
I ran a few tests on your code with aforementioned change of ranges <0,1),<1,2),<2,3), <3,4) making them even.
And you do it like that:
if (nextStep < 1) ++moveWest;
else if (nextStep < 2) ++moveEast;
else if (nextStep < 3) ++moveSouth;
else if (nextStep < 4)++moveNorth;
Notice <= becoming <.
100000 trials of 100 steps each gave those resutls:
Average distance is 8.873435509749317 steps away of from the starting point
W=2498906
E=2501447
N=2500022
S=2499625
,
where W,E,N,S are summed steps for given direction during all the trials.
They look fine.
Running such a test case for a couple of times reveals that there is no preferable direction. You might use other methods to get random numbers, but that would be testing generators, not your case. Your code looks ok from my point of view.
Sentence from the problem statement also gives you a clue:Theoretical answer: on the order of sqrt(N).
I think this line won't work :
nextStep = Math.random()*4;
the explanation is a logical one. I think it would be better to use Integers for your purpose because you want to calculate with steps, wich is a static unit. Well thats opinion based, but I recommend to count the full number of steps instead of tracking partial steps.
try this instead:
Random rand = new Random();
nextStep = rand.nextInt(4)+1; //random numbers {1,2,3,4}
Furthermore since nextInt() generates random Integer values you need to use the == operator instead of <= in your if/else statements.
if (nextStep == 1) ++moveWest;
else if (nextStep == 2) ++moveEast;
else if (nextStep == 3) ++moveSouth;
else if (nextStep == 4)++moveNorth;
regards to Tom (not me, the one in the comments!)
Related
Ice-Cream:
The beach stretches along the seacoast like a narrow strip. At some points of the beach the ice cream stalls are located. One day not all the ice cream sellers come to work. Distribute the sellers among the ice-cream stalls so that the minimum distance between them is as much as possible. So they will interfere less with each other.
Input:
The first line contains the number of stalls n (2 < n < 10001) and the number of ice cream sellers k (1 < k < n) at work. The second line contains n positive integers in increasing order - the coordinates of the stalls (the coordinates are not greater than 109).
Output:
Print one number - the minimum distance between the adjacent stalls in the optimal arrangement.
Input example:
5 3
1 2 3 100 1000
Output example:
99
This is what I have come up with so far. It is working not fast enough and I need other idea.
import java.util.Scanner;
public class Main
{
public static void main(String[] args)
{
Scanner s = new Scanner(System.in);
int[] n = new int[s.nextInt()];
int k = s.nextInt();
for(int i = 0; i < n.length; i++)
{n[i] = s.nextInt();}
int c = -1;
int[] cA = new int[k + 3]; //control array
for(int j = 1; j < cA.length; j++)
{cA[j] = j - 1;}
cA[k+1] = n.length;
cA[k+2] = 0;
while(true)
{
int currentCoordinate = -1, previousCoordinate = -1, minDist = -1;
for(int i = 1; i <= k; i++)
{
if(currentCoordinate == -1)
{currentCoordinate = n[cA[i]];}
else
{
previousCoordinate = currentCoordinate;
currentCoordinate = n[cA[i]];
int currentDistance = currentCoordinate - previousCoordinate;
if(minDist == -1 || minDist > currentDistance)
{minDist = currentDistance;}
}
}
if(minDist > c)
{c = minDist;}
int j = 1;
while(cA[j] + 1 == cA[j + 1])
{cA[j] = j - 1; j++;}
if(j > k)
{break;}
cA[j] = cA[j] + 1;
}
System.out.println(c);
}
}
This problem is solvable using binary search. First assume the answer is x. It means the minimum distance between two stalls is x. A greedy approach can verify this assumption. It is obvious that in the best configuration we have to use the leftmost stall (Can be easily proven by contradiction). Now traverse the points from left to right until the distance between the leftmost point and the rightmost point is less than x. Upon reaching to the first point (pi) that its distance to the leftmost point is bigger than x increment your counter. From now on your leftmost is px. Repeat this process until you reach the end of the points. Now if your counter is bigger than k it means that you can increase the value of x and vice versa.
So you can binary search to find the minimum value for x. This approach is in O(nLogn).
I am writing a Java program that calculates the largest prime factor of a large number. But I have an issue with the program's complexity, I don't know what has caused the program to run forever for large numbers, it works fine with small numbers.
I have proceeded as follow :
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
public class Largest_prime_factor {
public static void main(String[] args)
{
//ArrayList primesArray = new ArrayList();
ArrayList factorArray = new ArrayList();
long largest = 1;
long number = 600851475143L ;
long i, j, k;
//the array list factorArray will have all factors of number
for (i = 2; i < number; i++)
{
if( number % i == 0)
{
factorArray.add(i);
}
}
Here, the Array List will have all the factors of the number.
So I'll need to get only the prime ones, for that, I used a method that checks if a number is prime or not, if it's not a prime number, I remove it from the list using the following method :
java.util.ArrayList.remove()
So the next part of the code is as follow :
for (i = 2; i < number; i++)
{
if (!isPrime(i))
{
factorArray.remove(i);
System.out.println(factorArray);
}
}
System.out.println(Collections.max(factorArray));
}
The last line prints the largest number of factorArray, which is what I am looking for.
public static boolean isPrime(long n)
{
if(n > 2 && (n & 1) == 0)
return false;
for(int i = 3; i * i <= n; i += 2)
if (n % i == 0)
return false;
return true;
}
}
The function above is what I used to determine if the number is a prime or not before removing it from the list.
This program works perfectly for small numbers, but it takes forever to give an output for large numbers, although the last function is pretty fast.
At first, I used to check if a number is prime or not inside of the first loop, but it was even slower.
You are looping over 600851475143 numbers.
long number = 600851475143L ;
for (i = 2; i < number; i++)
Even if we assume that each iteration takes very very small time (as small as 1 microsecond), it'll still take days before the loop finishes.
You need to optimise your prime-finding logic in order for this program to run faster.
One way to reduce the iterations to reasonable number is to loop until square root of number.
for (i = 2; i < Math.sqrt(number); i++)
or
for (i = 2; i*i < number; i++)
The calculation of the prime factors of 600851475143L should take less than a milli-second (with a not totally inefficient algorithm). The main parts your code is currently missing:
The border should be sqrt(number) and not number.
The current value should be checked in a while-loop (to prevent that non-prime-factors are added to the list, reduces range to check).
The max. value should be decreased (as well as the border) to number/factor after finding a factor.
Further improvements are possible, e.g. to iterate only over non-even numbers (or only iterate over numbers that are neither a multiple of 2 and 3) etc.
An example implementation for the same question on codereview (link):
public static long largestPrimeFactor(
final long input) {
////
if (input < 2)
throw new IllegalArgumentException();
long n = input;
long last = 0;
for (; (n & 1) == 0; n >>= 1)
last = 2;
for (; n % 3 == 0; n /= 3)
last = 3;
for (long v = 5, add = 2, border = (long) Math.sqrt(n); v <= border; v += add, add ^= 6)
while (n % v == 0)
border = (long) Math.sqrt(n /= last = v);
return n == 1 ? last : n;
}
for (i = 2; i < number; i++)
{
if( number % i == 0)
{
factorArray.add(i);
}
}
For an large input size, you will be visiting up to the value of the number. Same for the loop of removing factors.
long number = 600851475143L ;
this is a huge number, and you're looping through this twice. Try putting in a count for every 10,000 or 100,000 (if i%10000 print(i)) and you'll get an idea of how fast it's moving.
One of the possible solutions is to only test if the the prime numbers smaller than the large number divide it.
So I checked
for (i=2; i < number; i++)
{
if(isPrime(i))
{
if( number % i == 0)
{
factorArray.add(i);
}
}
}
So here I'll only be dividing by prime numbers instead of dividing by all numbers smaller than 600851475143.
But this is still not fast, a complete modification of the algorithm is necessary to obtain an optimal one.
#Balkrishna Rawool suggestion is the right way to go. For that I would suggest to change the iteration like this: for (i = 3; i < Math.sqrt(number); i+=2) and handle the 2 manually. That will decrease your looping because none of the even numbers except 2 are prime.
Fill array a from a[0] to a[n-1]: generate random numbers until you get one that is not already in the previous indexes.
This is my implementation:
public static int[] first(int n) {
int[] a = new int[n];
int count = 0;
while (count != n) {
boolean isSame = false;
int rand = r.nextInt(n) + 1;
for (int i = 0; i < n; i++) {
if(a[i] == rand) isSame = true;
}
if (isSame == false){
a[count] = rand;
count++;
}
}
return a;
}
I thought it was N^2 but it's apparently N^2logN and I'm not sure when the log function is considered.
The 0 entry is filled immediately. The 1 entry has probability 1 - 1 / n = (n - 1) / n of getting filled by a random number. So we need on average n / (n - 1) random numbers to fill the second position. In general, for the k entry we need on average n / (n - k) random numbers and for each number we need k comparisons to check if it's unique.
So we need
n * 1 / (n - 1) + n * 2 / (n - 2) + ... + n * (n - 1) / 1
comparisons on average. If we consider the right half of the sum, we see that this half is greater than
n * (n / 2) * (1 / (n / 2) + 1 / (n / 2 - 1) + ... + 1 / 1)
The sum of the fractions is known to be Θ(log(n)) because it's an harmonic series. So the whole sum is Ω(n^2*log(n)). In a similar way, we can show the sum to be O(n^2*log(n)). This means on average we need
Θ(n^2*log(n))
operations.
This is similar to the Coupon Collector problem. You pick from n items until you get one you don't already have. On average, you have O(n log n) attempts (see the link, the analysis is not trivial). and in the worst case, you examine n elements on each of those attempts. This leads to an average complexity of O(N^2 log N)
The algorithm you have is not O(n^2 lg n) because the algorithm you have may loop forever and not finish. Imagine on your first pass, you get some value $X$ and on every subsequent pass, trying to get the second value, you continue to get $X$ forever. We're talking worst case here, after all. That would loop forever. So since your worst case is never finishing, you can't really analyze.
In case you're wondering, if you know that n is always both the size of the array and the upper bound of the values, you can simply do this:
int[] vals = new int[n];
for(int i = 0; i < n; i++) {
vals[i] = i;
}
// fischer yates shuffle
for(int i = n-1; i > 0; i--) {
int idx = rand.nextInt(i + 1);
int t = vals[idx];
vals[idx] = vals[i];
vals[i] = t;
}
One loop down, one loop back. O(n). Simple.
If I'm not mistaken, the log N part comes from this part:
for(int i = 0; i < count; i++){
if(a[i] == rand) isSame = true;
}
Notice that I changed n for count because you know that you have only count elements in your array on each loop.
Write a program that computes the following equation.
100/1+99/2+98/3+97/4+96/5...3/98+2/99+1/100
I am not asking for a solution. Yes this is a homework problem, but I am not here to copy paste the answers. I asked my professor to explain the problem or how should I approach this problem? She said "I can't tell you anything."
public static void main(String[] args){
int i;
for(i = 100; i >= 1; i--)
{
int result = i/j;
j = j+1;
System.out.println(result);
}
}
You can try to observe a "trend" or "pattern" when solving questions of this type.
Given: 100/1+99/2+98/3+97/4+96/5...3/98+2/99+1/100
We derived: Numerator/Denominator, let's call it n divide by d (n/d)
Pattern Observed:
n - 1 after every loop
d + 1 after every loop
So, if you have 100 numbers, you need to loop 100 times. Thus using a for-loop which loops 100 times will seemed appropriate:
for(int n=0; n<100; n++) //A loop which loops 100 times from 0 - 100
To let n start with 100, we change the loop a little to let n start from 100 instead of 0:
for(int n=100; n>0; n--) //A loop which loops 100 times from 100 - 0
You settled n, now d needs to start from 1.
int d = 1; //declare outside the loop
Putting everything together, you get:
int d = 1;
double result = 0.0;
for (int n=100; n>0; x--)
{
result += (double)n/d; //Cast either n or d to double, to prevent loss of precision
d ++; //add 1 to d after every loop
}
You are on the right track. You need to loop like you've done, but then you need to SUM up all the results. In your example you can try:
result = result + i/j;
or
result += i/j;
Note that the declaration of result needs to be outside the loop otherwise you are always initializing it.
Also think about the division (hint), you are dividing integers...
What you have is a series.
There is more than one way to define a series, but all things being the same it's more intuitive to have the index of a series increase rather than decrease.
In this case, you could use i from 0 to 99.
Which in java can be:
double sum = 0;
for (int i = 0; i < 100; i++) {
sum += (100 - i) / (double) (1 + i);
}
if you want the result in the same format then do :
int j = 100;
double sum=0;
for (int i = 1; i <= 100; i++) {
sum += ((double) j / i); // typecast as least one of i or j to double.
System.out.print(j + "/" + i+"+");
j--;
}
// here print the sum
I am very beginner on Java, still getting passion about.
I have been given this exercise: "Write a simulator program that flips a coin: One thousand times then prints out how many time you get tails and how many times you get heads"
That is what i have tried to do so far.
import java.util.Random;
import java.util.regex.Pattern;
public class coin {
public static void main( String [] args ) {
Random r = new Random();
Pattern tail = Pattern.compile("Tail+");
Pattern head = Pattern.compile("Head+");
String flips = "";
for (int i = 0; i < 1000; i++) {
flips += r.nextInt(100) % 2 == 0 ? "Head" : "Tail";
}
String[] heads = head.split( flips );
String[] tails = tail.split( flips );
//Display
System.out.println("Times head was flipped:" + heads.length);
System.out.println("Times tail was flipped:" + tails.length);
}
}
The program seems to be working, but it is giving me always an almost pair amount of heads and tails, which the total exceed 1000, at least by 1 or more.
Please, someone has any solution of this? Where am I wrong?
Thanks
Rather than appending the result in a String and then splitting the string and counting the occurence of "Head"/"Tail" you can just keep track of the count in separate variables :
int headCount = 0;
int tailCount = 0;
for (int i = 0; i < 1000; i++) {
if(r.nextInt(100) %2 == 0)
{
headCount++;
}
else
{
tailCount ++;
}
System.out.println("Times head was flipped:" + headsCount);
System.out.println("Times tail was flipped:" + tailCount);
}
A coin has two sides, so I really don't see why you would ask the random generator to generate a number between 0 and 100 (exclusive). Between 0 and 2 (exclusive) would be much more logical.
Also, you're being asked to count. Appending strings and then splitting to get the final value is quite a complex and inefficient way to count. You should use an integer instead. Each time you get a 1 from your random, increment a counter. In the end, you have the number of times 1 was returned, and the number of 0 is thus 1000 - this number.
Random r = new Random();
int heads = 0;
for (int i = 0; i < 1000; i++) {
int side = random.nextInt(2);
if (side == 1) {
heads++;
}
}
System.out.println("Times head was flipped:" + heads);
System.out.println("Times tail was flipped:" + (1000 - heads));
It could even be simplified to the follwoing (although this simplification makes the code a bit harder to understand):
Random r = new Random();
int heads = 0;
for (int i = 0; i < 1000; i++) {
heads += random.nextInt(2);
}
System.out.println("Times head was flipped:" + heads);
System.out.println("Times tail was flipped:" + (1000 - heads));
I had similar question for my assessment and I tried below code and it worked. May be its not appropriate way of doing.
I am happy to receive feedback! thanks.
for (int i = 1; i < 1000; i++) {
flips += r.nextInt(100) % 2 == 1 ? "Head" : "Tail";
}