Related
I was going through this problem in one of exam paper and found one solution in answer book. I am not able to understand algorithm behind it. Can anyone explain me how this algorithm works?
Given n non-negative integers representing an elevation map where the width of each bar is 1, compute how much water it is able to trap after raining.
For example, Given the input
[0,1,0,2,1,0,1,3,2,1,2,1]
the return value would be
6
Solution as per answer book is this
public class Solution {
public int trap(int[] height) {
if (height.length <=2 )
return 0;
int h = 0, sum = 0, i = 0, j = height.length - 1;
while(i < j)
{
if ( height[i] < height[j] )
{
h = Math.max(h,height[i]);
sum += h - height[i];
i++;
}
else
{
h = Math.max(h,height[j]);
sum += h - height[j];
j--;
}
}
return sum;
}
}
Thanks
WoDoSc was nice enough to draw a diagram of the elevations and trapped water. The water can only be trapped between two higher elevations.
What I did was run the code and output the results so you can see how the trapped water is calculated. The code starts at both ends of the "mountain" range. Whichever end is lower is moved closer to the center.
In the case where the two ends are the same height, the right end is moved closer to the center. You could move the left end closer to the center instead.
The first column is the height and index of the elevations on the left. The second column is the height and index of the elevations on the right.
The third column is the maximum minimum height. In other words, the maximum height of the left or the right, whichever maximum is smaller. This number is important to determine the local water level.
The fourth column is the sum.
Follow along with the diagram and you can see how the algorithm works.
0,0 1,11 0 0
1,1 1,11 1 0
1,1 2,10 1 0
0,2 2,10 1 1
2,3 2,10 2 1
2,3 1,9 2 2
2,3 2,8 2 2
2,3 3,7 2 2
1,4 3,7 2 3
0,5 3,7 2 5
1,6 3,7 2 6
6
And here's the code. Putting print and println statements in appropriate places can help you understand what the code is doing.
package com.ggl.testing;
public class RainWater implements Runnable {
public static void main(String[] args) {
new RainWater().run();
}
#Override
public void run() {
int[] height = { 0, 1, 0, 2, 1, 0, 1, 3, 2, 1, 2, 1 };
System.out.println(trap(height));
}
public int trap(int[] height) {
if (height.length <= 2) {
return 0;
}
int h = 0, sum = 0, i = 0, j = height.length - 1;
while (i < j) {
System.out.print(height[i] + "," + i + " " + height[j] + "," + j
+ " ");
if (height[i] < height[j]) {
h = Math.max(h, height[i]);
sum += h - height[i];
i++;
} else {
h = Math.max(h, height[j]);
sum += h - height[j];
j--;
}
System.out.println(h + " " + sum);
}
return sum;
}
}
I know that probably it's not the best way to represent it graphically, but you can imagine the situation as the following figure:
Where the red bars are the terrain (with elevations according to the array of your example), and the blue bars are the water that can be "trapped" into the "valleys" of the terrain.
Simplifying, the algorithm loops all the bar left-to-right (if left is smaller) or right-to-left (if right is smaller), the variable h stores the maximum height found during each step of the loop, because the water can not be higher than the maximum height of the terrains, and to know how much water can be trapped, it sums the differences between the height of the water (maximum height h) and the elevation of the terrain on a specific point, to get the actual quantity of water.
The algorithm works by processing the land from the left (i) and the right (j).
i and j are counters that work towards each other approaching the middle of the land.
h is a variable that tracks the max height found thus far considering the lower side.
The land is processed by letting i and j worked "toward each other." When I read the code, I pictured two imaginary walls squeezing the water toward the middle where the lowest wall moves toward the higher wall. The algorithm continues to sum up the volume of water. It uses h - height[x] because water can only be contained by inside the lowest point between two walls. So essentially it continues to sum up the volume of water from the left and right and subtracts out and water displaced by higher elevation blocks.
Maybe better variable names would have been
leftWall instead of i
rightWall instead of j
waterMaxHeight instead
of h
I think above solution is difficult to understand.I have a simple solution which take o(n) extra space & o(n) time complexity.
Step of algorithm
1.Maintain an array which contain maximum of all element which is right side of current element.
2.maintain a variable max from left side which contain maximum of all element which is left side of current element.
3.find minimum of max from left & max from right which is already present in array.
4.if minimum value is greater than the current value in array than add difference of than in ans & add the difference with current value & update max from left.
import java.util.*;
import java.lang.*;
import java.io.*;
class Solution
{
public static void main (String[] args) throws java.lang.Exception
{
int[] array= {0, 1, 0, 2, 1, 0, 1, 3, 2, 1, 2, 1 };
int[] arrayofmax=new int[array.length];
int max=0;
arrayofmax[array.length-1]=0;
for(int x=array.length-1;x>0;x--){
if(max<array[x]){
max=array[x];
}
arrayofmax[x-1]=max;
}
int ans=0;
int maxfromleft=0;
for(int i=0;i<array.length-1;i++){
if(maxfromleft<array[i]){
maxfromleft=array[i];
}
int min=maxfromleft>arrayofmax[i+1]?arrayofmax[i+1]:maxfromleft;
if(min>array[i+1]){
ans+=min-array[i+1];
array[i+1]=min;
}
}
System.out.println(ans);
}
}
May be my algorithm is same as above but i think this implementation is easy to understand
Trapping Rain Water problem solved in Java.
class Store
{
static int arr[] = new int[]{0, 1, 0, 2, 2};
// Method for maximum amount of water
static int StoreWater(int n)
{
int max = 0;
int f = 0;
for (int i = 1; i < n; i++)
{
max = Math.max(arr[i], max);
f += Math.max(arr[i], max) - arr[i];
}
return f;
}
public static void main(String[] args)
{
System.out.println("Maximum water that can be accumulated is " +
findWater(arr.length));
}
}
Here is a different and easy approach for water trapping problem. O(1) space and O(N) time complexity.
Logic:
-> Let’s loop from 0 index to the end of the input values.
-> If we find a wall greater than or equal to the previous wall
-> make note of the index of that wall in a var called prev_index
-> keep adding previous wall’s height minus current (ith) wall to the variable water.
-> have a temp variable that also stores the same value as water.
-> Loop till the end, if you dont find any wall greater than or equal to the previous wall, then quit.
-> If the above point is true (i.e, if prev_index < size of input array), then subtract the temp variable from water, and loop from end of the input array to prev_index and find a wall greater than or equal to the previous wall (in this case, the last wall from backwards)
The concept here is if there is a larger wall to the right you can retain water with height equal to the smaller wall on the left.
If there are no larger walls to the right, then start from left. There must be a larger wall to your left now.
You're essentially looping twice, so O(2N), but asymptotically O(N), and of course O(1) space.
JAVA Code Here:
class WaterTrap
{
public static void waterTrappingO1SpaceOnTime(){
int arr[] = {1,2,3,2,1,0}; // answer = 14
int size = arr.length-1;
int prev = arr[0]; //Let first element be stored as previous, we shall loop from index 1
int prev_index = 0; //We need to store previous wall's index
int water = 0;
int temp = 0; //temp will store water until a larger wall is found. If there are no larger walls, we shall delete temp value from water
for(int i=1; i<= size; i++){
if(arr[i] >= prev){ // If current wall is taller then previous wall, make current wall as the previous wall, and its index as previous wall's index for the subsequent loops
prev = arr[i];
prev_index = i;
temp = 0; //because larger or same height wall is found
} else {
water += prev - arr[i]; //Since current wall is shorter then previous, we subtract previous wall height from current wall height and add to water
temp += prev - arr[i]; // Store same value in temp as well, if we dont find larger wall, we will subtract temp from water
}
}
// If the last wall was larger than or equal to the previous wall, then prev_index would be equal to size of the array (last element)
// If we didn't find a wall greater than or equal to the previous wall from the left, then prev_index must be less than index of last element
if(prev_index < size){
water -= temp; //Temp would've stored the water collected from previous largest wall till the end of array if no larger wall was found. So it has excess water. Delete that from 'water' var
prev = arr[size]; // We start from the end of the array, so previous should be assigned to the last element.
for(int i=size; i>= prev_index; i--){ //Loop from end of array up to the 'previous index' which would contain the "largest wall from the left"
if(arr[i] >= prev){ //Right end wall will be definitely smaller than the 'previous index' wall
prev = arr[i];
} else {
water += prev - arr[i];
}
}
}
System.out.println("MAX WATER === " + water);
}
public static void main(String[] args) {
waterTrappingO1SpaceOnTime();
}
}
Algorithm:
1.Create two array left and right of size n. create a variable max_ = INT_MIN.
2.Run one loop from start to end. In each iteration update max_ as max_ = max(max_, arr[i]) and also assign left[i] = max_
3.Update max_ = INT_MIN.
4.Run another loop from end to start. In each iteration update max_ as max_ = max(max_, arr[i]) and also assign right[i] = max_
5.Traverse the array from start to end.
6.The amount of water that will be stored in this column is min(a,b) – array[i],(where a = left[i] and b = right[i]) add this value to total amount of water stored
7.Print the total amount of water stored.
Code:
/*** Theta(n) Time COmplexity ***/
static int trappingRainWater(int ar[],int n)
{
int res=0;
int lmaxArray[]=new int[n];
int rmaxArray[]=new int[n];
lmaxArray[0]=ar[0];
for(int j=1;j<n;j++)
{
lmaxArray[j]=Math.max(lmaxArray[j-1], ar[j]);
}
rmaxArray[n-1]=ar[n-1];
for(int j=n-2;j>=0;j--)
{
rmaxArray[j]=Math.max(rmaxArray[j+1], ar[j]);
}
for(int i=1;i<n-1;i++)
{
res=res+(Math.min(lmaxArray[i], rmaxArray[i])-ar[i]);
}
return res;
}
python code
class Solution:
def trap(self, h: List[int]) -> int:
i=0
j=len(h)-1
ml=-1
mr=-1
left=[]
right=[]
while(i<len(h)):
if ml<h[i]:
ml=h[i]
left.append(ml)
if mr<h[j]:
mr=h[j]
right.insert(0,mr)
i=i+1
j=j-1
s=0
for i in range(len(h)):
s=s+min(left[i],right[i])-h[i]
return s
I have create a program that takes a random array which is created by starting from 0 and adding Math.random() (double between 0 and 0.999) n times, and calculates the weighted average of each position within a certain radius. I currently have a program that does this but i was wondering how to create one using a torus. The basic principle is the last element is now equal to the first element and when the first element updates its position it takes into account the difference between the other elements including some of the last elements in the array.
Any help on the matter would be much appreciated. Its not help with the coding but with the principle behind it, I cant work out how this would be possible for multiple iterations.
heres the code so far that works for one iteration. After one the code is incorrect and calculates the wrong values.
import java.text.DecimalFormat;
import java.util.Scanner;
/**
* Created by jameshales on 12/03/2014.
*/
public class Torus {
public static void main(String[] args) {
DecimalFormat df = new DecimalFormat("#.###"); // this sets all decimals to a max of 3 decimal places.
System.out.println("how many numbers of agents on the real line?"); // This asks the question "how many numbers on the real line?" to the user.
Scanner input = new Scanner(System.in);
int n = 0;
n=Integer.parseInt(input.nextLine()); // the scanner reads the input and assigns it to the variable n
double[] agentPosition = new double[n]; // create an array with decimal places allowed called agentPosition
double[] newAgentPosition = new double[n]; // create an array with decimal places allowed called newAgentPosition
double[] originalAgentPosition = new double[n]; // create an array with decimal places allowed called originalAgentPosition
System.out.println("Please select your desired radius? select 1 normally"); // This asks the question "Please select your desired radius?
double r = 0;
r = input.nextDouble(); // the scanner reads the next input and assigns it to the variable r
int t = 0; // sets t to 0
double epsilon = 0.001; // this allows us to sets epsilon to 0.
// start the array from position 0 with its value set to 0
for (int i = 0; i <= n - 1; i++) { // starting from position 1 it creates a random number between 0 and 0.999 and adds it to the previous agentPosition to fill the array in a random increasing way.
if (i > 0)
agentPosition[i] = agentPosition[i - 1] + Math.random(); // this equation creates the random array
else agentPosition[i] =0.0;
}
System.arraycopy(agentPosition,0,originalAgentPosition,0,n);
// This takes the first randomly created array(agentPosition), copyies each element starting from 0 to n and calls it originalAgentPosition.
while(true) { // This is the start of the while loop, this will keep running until false
for (int i = 0; i <= n - 1; i++) {
// this will go through the array 1 position at a time in an increasing order from position 0 to n-1
double total1 = agentPosition[i]; // sets the initial value of total1 to 0
double total2 = 0; // sets the initial value of total2 to 0
int numposition = 1; // this starts at 1 so it includes the position in the array when dividing.(also stops dividing by 1)
for (int j = i - 1; j >= 0; j--) { // this will work from the initial value of the array to the one before the one selected.
if ((agentPosition[i] - agentPosition[j]) <= r) { // this calculates the absolute value of the difference between 2 positions on the array. (from i working downwards)
numposition++; // this sums the number of positions within the radius of the chosen position.
total1 += agentPosition[j]; // this sums up all the values within the radius below to the total1.
} else break; // stops the program once it has passed a position of a distance of 1
}
for (int k = i + 1; k <= n - 1 ; k++) { // this will go from the one after the position selected to the last position in the array to test if the distance is greater than 1, stops otherwise..
if (Math.abs(agentPosition[k] - agentPosition[i]) <= r) { // this calculates the absolute value of the difference between 2 positions on the array(i and positions greater).
numposition++; // this sums the number of positions within the radius of the chosen position.
total2 += agentPosition[k]; // this sums up all the values within the radius above to the total1.
} else break; // stops the program once it has passed a position of a distance of 1
}
for (int j = n - 2; j >= 1; j--) { // this will work from the initial value of the array to the one before the one selected.
if (((agentPosition[n-1] + agentPosition[i]) - agentPosition[j]) <= r) { // this calculates the absolute value of the difference between 2 positions on the array. (from i working downwards)
numposition++;
total1 += (agentPosition[j] - agentPosition[n - 1]); // this sums up all the values within the radius below to the total1.
} else break;// stops the program once it has passed a position of a distance of 1
}
for (int k = 1; k <= n - 2 ; k++) { // this will go from the one after the position selected to the last position in the array to test if the distance is greater than 1, stops otherwise..
if (Math.abs((agentPosition[i] - agentPosition[n - 1]) - agentPosition[k]) <= r) { // this calculates the absolute value of the difference between 2 positions on the array(i and positions greater).
numposition++; // this sums the number of positions within the radius of the chosen position.
total2 += (agentPosition[n - 1] + agentPosition[k]); // this sums up all the values within the radius above to the total1.
} else break;// stops the program once it has passed a position of a distance of 1
}
newAgentPosition[i] = (total1 + total2) / numposition; // this calculates the new weighted average. ( sum of assigned random variable/ sum of position)
}
for (int i = 0; i <= n - 1; i++){
if (newAgentPosition[i] > originalAgentPosition[n - 1]){
newAgentPosition[i] = newAgentPosition[i] - originalAgentPosition[n - 1];
}
if(newAgentPosition[i] < 0) { // This checks if the agentPosition is smaller than 0 and then adds the largest agent to make all the elements within the range.
newAgentPosition[i] = newAgentPosition[i] + originalAgentPosition[n - 1];
}
}
t++; // This sums up how many iterations it will take.
double largestDiff = 0.0; // This assigns largestDiff to 0
for (int i = 0; i <= n-1; i++) {
double diff = Math.abs(agentPosition[i] - newAgentPosition[i]); // This calculates the difference between the previous and current array at position i.
if(diff > largestDiff) // If the difference between the agents is bigger than 0, assign it to the variable largestDiff.
largestDiff = diff;
}
if(largestDiff <= epsilon){ // This checks if the difference is bigger than the set epsilon,
break; // This stops the program if the difference is smaller than epsilon
}
agentPosition = new double[n];
System.arraycopy(newAgentPosition, 0, agentPosition, 0, n); // This takes the newly generated array(newAgentPosition), copyies each element starting from 0 to n and assigns it back to agentPosition. (this stops the problem j and with taking the newly created elements.)
}
for (int i = 0 ; i <= n - 1; i++) { // starting from position 1 it creates a random number between 0 and 0.999 and adds it to the previous agentPosition to fill the array in a random increasing way.
System.out.println(i + ": " + df.format(originalAgentPosition[i]) + "\t->\t" + df.format(agentPosition[i]));
}
int sumdofclusters = 1; // This sets the sum of clusters to 1
System.out.println("The different clusters are:\n" + df.format(agentPosition[0])); // This prints out the first cluster only.
for (int i = 1; i <= n - 1 ; i++) {
if(Math.abs(agentPosition[i] - agentPosition[i - 1]) >= epsilon) { // This checks if the element after the element at hand is different by a set epsilon.(how to work out different clusters)
sumdofclusters++; // This sums the number of clusters.
System.out.println(df.format(agentPosition[i])); // This prints out the different clusters other than the first 1.
}
}
System.out.println("Number of clusters is:" + sumdofclusters); // This prints out the number of clusters.
System.out.println("Number of iterations:" + t); // This prints out the number of iterations.
}
}
You can create a circular list using an array with modulus division.
getElementAt(double[] arr, int index)
{
index = index % arr.length;
index = index + arr.length; // If index is negative, modulus division gives us negative result, so this makes it positive.
index = index % arr.length; // In case the previous step made index >= n
return arr[index]
}
If n is arr.length then
0 <= index < n will be like normal.
n <= index will wrap around the list (e.g. arr[n] == arr[0], arr[n+1] == arr[1], etc.)
index < 0 will wrap around the list in the other direction (e.g. arr[-1] == arr[n-1], arr[-2] == arr[n-2], etc.)
This question is an extension of Java- Math.random(): Selecting an element of a 13 by 13 triangular array. I am selecting two numbers at random (0-12 inclusive) and I wanted the values to be equal.
But now, since this is a multiplication game, I want a way to bias the results so certain combinations come up more frequently (like if the Player does worse for 12x8, I want it to come up more frequently). Eventually, I would like to bias towards any of the 91 combinations, but once I get this down, that should not be hard.
My Thoughts: Add some int n to the triangular number and Random.nextInt(91 + n) to bias the results toward a combination.
private int[] triLessThan(int x, int[] bias) { // I'm thinking a 91 element array, 0 for no bias, positive for bias towards
int i = 0;
int last = 0;
while (true) {
int sum = 0;
for (int a = 0; a < i * (i + 2)/2; a++){
sum += bias[a]
}
int triangle = i * (i + 1) / 2;
if (triangle + sum > x){
int[] toReturn = {last,i};
return toReturn;
}
last = triangle;
i++;
}
}
At the random number roll:
int sum = sumOfArray(bias); // bias is the array;
int roll = random.nextInt(91 + sum);
int[] triNum = triLessThan(roll);
int num1 = triNum[1];
int num2 = roll - triNum[0]; //now split into parts and make bias[] add chances to one number.
where sumOfArray just finds the sum (that formula is easy). Will this work?
Edit: Using Floris's idea:
At random number roll:
int[] bias = {1,1,1,...,1,1,1} // 91 elements
int roll = random.nextInt(sumOfBias());
int num1 = roll;
int num2 = 0;
while (roll > 0){
roll -= bias[num2];
num2++;
}
num1 = (int) (Math.sqrt(8 * num2 + 1) - 1)/2;
num2 -= num1 * (num1 + 1) / 2;
You already know how to convert a number between 0 and 91 and turn it into a roll (from the answer to your previous question). I would suggest that you create an array of N elements, where N >> 91. Fill the first 91 elements with 0...90, and set a counter A to 91. Now choose a number between 0 and A, pick the corresponding element from the array, and convert to a multiplication problem. If the answer is wrong, append the number of the problem to the end of the array, and increment A by one.
This will create an array in which the frequencies of sampling will represent the number of times a problem was solved incorrectly - but it doesn't ever lower the frequency again if the problem is solved correctly the next time it is asked.
An alternative and better solution, and one that is a little closer to yours (but distinct) creates an array of 91 frequencies - each initially set to 1 - and keeps track of the sum (initially 91). But now, when you choose a random number (between 0 and sum) you traverse the array until the cumulative sum is greater then your random number - the number of the bin is the roll you choose, and you convert that with the formula derived earlier. If the answer is wrong you increment the bin and update the sum; if it is right, you decrement the sum but never to a value less than one, and update the sum. Repeat.
This should give you exactly what you are asking: given an array of 91 numbers ("bins"), randomly select a bin in such a way that the probability of that bin is proportional to the value in it. Return the index of the bin (which can be turned into the combination of numbers using the method you had before). This function is called with the bin (frequency) array as the first parameter, and the cumulative sum as the second. You look up where the cumulative sum of the first n elements first exceeds a random number scaled by the sum of the frequencies:
private int chooseBin(float[] freq, float fsum) {
// given an array of frequencies (probabilities) freq
// and the sum of this array, fsum
// choose a random number between 0 and 90
// such that if this function is called many times
// the frequency with which each value is observed converges
// on the frequencies in freq
float x, cs=0; // x stores random value, cs is cumulative sum
int ii=-1; // variable that increments until random value is found
x = Math.rand();
while(cs < x*fsum && ii<90) {
// increment cumulative sum until it's bigger than fraction x of sum
ii++;
cs += freq[ii];
}
return ii;
}
I confirmed that it gives me a histogram (blue bars) that looks exactly like the probability distribution that I fed it (red line):
(note - this was plotted with matlab so X goes from 1 to 91, not from 0 to 90).
Here is another idea (this is not really answering the question, but it's potentially even more interesting):
You can skew your probability of choosing a particular problem by sampling something other than a uniform distribution. For example, the square of a uniformly sampled random variate will favor smaller numbers. This gives us an interesting possibility:
First, shuffle your 91 numbers into a random order
Next, pick a number from a non-uniform distribution (one that favors smaller numbers). Since the numbers were randomly shuffled, they are in fact equally likely to be chosen. But now here's the trick: if the problem (represented by the number picked) is solved correctly, you move the problem number "to the top of the stack", where it is least likely to be chosen again. If the player gets it wrong, it is moved to the bottom of the stack, where it is most likely to be chosen again. Over time, difficult problems move to the bottom of the stack.
You can create random distributions with different degrees of skew using a variation of
roll = (int)(91*(asin(Math.rand()*a)/asin(a)))
As you make a closer to 1, the function tends to favor lower numbers with almost zero probability of higher numbers:
I believe the following code sections do what I described:
private int[] chooseProblem(float bias, int[] currentShuffle) {
// if bias == 0, we choose from uniform distribution
// for 0 < bias <= 1, we choose from increasingly biased distribution
// for bias > 1, we choose from uniform distribution
// array currentShuffle contains the numbers 0..90, initially in shuffled order
// when a problem is solved correctly it is moved to the top of the pile
// when it is wrong, it is moved to the bottom.
// return value contains number1, number2, and the current position of the problem in the list
int problem, problemIndex;
if(bias < 0 || bias > 1) bias = 0;
if(bias == 0) {
problem = random.nextInt(91);
problemIndex = problem;
}
else {
float x = asin(Math.random()*bias)/asin(bias);
problemIndex = Math.floor(91*x);
problem = currentShuffle[problemIndex];
}
// now convert "problem number" into two numbers:
int first, last;
first = (int)((Math.sqrt(8*problem + 1)-1)/2);
last = problem - first * (first+1) / 2;
// and return the result:
return {first, last, problemIndex};
}
private void shuffleProblems(int[] currentShuffle, int upDown) {
// when upDown==0, return a randomly shuffled array
// when upDown < 0, (wrong answer) move element[-upDown] to zero
// when upDown > 0, (correct answer) move element[upDown] to last position
// note - if problem 0 is answered incorrectly, don't call this routine!
int ii, temp, swap;
if(upDown == 0) {
// first an ordered list:
for(ii=0;ii<91;ii++) {
currentShuffle[ii]=ii;
}
// now shuffle it:
for(ii=0;ii<91;ii++) {
temp = currentShuffle[ii];
swap = ii + random.nextInt(91-ii);
currentShuffle[ii]=currentShuffle[swap];
currentShuffle[swap]=temp;
}
return;
}
if(upDown < 0) {
temp = currentShuffle[-upDown];
for(ii = -upDown; ii>0; ii--) {
currentShuffle[ii]=currentShuffle[ii-1];
}
currentShuffle[0] = temp;
}
else {
temp = currentShuffle[upDown];
for(ii = upDown; ii<90; ii++) {
currentShuffle[ii]=currentShuffle[ii+1];
}
currentShuffle[90] = temp;
}
return;
}
// main problem posing loop:
int[] currentShuffle = new int[91];
int[] newProblem;
int keepGoing = 1;
// initial shuffle:
shuffleProblems( currentShuffle, 0); // initial shuffle
while(keepGoing) {
newProblem = chooseProblem(bias, currentShuffle);
// pose the problem, get the answer
if(wrong) {
if(newProblem > 0) shuffleProblems( currentShuffle, -newProblem[2]);
}
else shuffleProblems( currentShuffle, newProblem[2]);
// decide if you keep going...
}
so I'm currently working on an assignment that I just can't seem to finish. Well I have everything finished but would like the extra credit. I've been looking around the web and can't really seem to find exactly what I'm looking for.
public class PascalTester
{
public static void main(String[] args)
{
Scanner kb = new Scanner(System.in);
System.out.println("Welcome to the Pascal's Triangle program!");
System.out.println("Please enter the size of the triangle you want");
int size = kb.nextInt();
int[][] myArray = new int[size][size];
myArray = fillArray(myArray);
//myArray = calculateArray(myArray);
printArray(myArray); //prints the array
}
private static int[][] fillArray(int[][] array)
{
array[0][1] = 1;
for (int i = 1; i < array.length; i++)
{
for (int j = 1; j < array[i].length; j++)
{
array[i][j] = array[i-1][j-1] + array[i-1][j];
}
}
return array;
}
private static void printArray(int[][] array)
{
for (int i = 0; i < array.length; i++)
{
for (int j = 0; j < array[i].length; j++)
{
if(array[i][j] != 0)
System.out.print(array[i][j] + " ");
}
System.out.println();
}
}
}
The only issue that I'm having now is to properly format the output to look like an actual triangle. Any suggestions would be very helpful at this point in time. Thanks in advance
One approach to this, is, assuming you have all numbers formatted to the same width, is to treat the problem as that of centering the lines.
Java Coding left as exercise to reader but essentially:
for lineText : triange lines
leadingSpacesCount = (80/2) - lineText.length();
print " " x leadingSpacesCount + lineText
Try to use the technique at http://www.kodejava.org/examples/16.html to make an array with array.length - i - 1 spaces (need to add the number spaces between numbers.. and 2 number of 2 digit numbers if any..).
Print this array at the start of the outer for loop.
The challenge here is that you want to start printing at the top of the triangle, but you don't know where to center each row until you get to the last (and widest) row of the triangle. The trick is to not print anything until you know how wide the last row is. One way to do this is to generate all the rows as String (or StringBuilder) objects and compute the maximum width. Then, from the top, center each line by first printing an appropriate number of spaces. The correct number of spaces will be
(maxLineLength - currentLine.length()) / 2
Alternatively, you can simply assume a maximum line length and center all lines in that width. If the longer lines exceed the maximum width, then the triangle will be distorted below a certain row. (Just be sure to not try printing a negative number of spaces!)
If anyone is looking for the actual code to do this take a look at my implementation in Java, it's similar to what Craig Taylor mentioned (numbers formatted to the same width) plus it uses an algorithm to compute the elements without memory (or factorials).
The code has comments explaining each step (calculation and printing):
/**
* This method will print the first # levels of the Pascal's triangle. It
* uses the method described in:
*
* https://en.wikipedia.org/wiki/Pascal%27s_triangle#Calculating_a_row_or_diagonal_by_itself
*
* It basically computes the Combinations of the current row and col
* multiplied by the previous one (which will always be 1 at the beginning
* of each pascal triangle row). It will print each tree element to the output
* stream, aligning the numbers with spaces to form a perfect triangle.
*
* #param num
* # of levels to print
*/
public static void printPascalTriangle(int num) {
// Create a pad (# of spaces) to display between numbers to keep things
// in order. This should be bigger than the # of digits of the highest
// expected number and it should be an odd number (to have the same
// number of spaces to the left and to the right between numbers)
int pad = 7;
// Calculate the # of spaces to the left of each number plus itself
// (this is the width of the steps of the triangle)
int stepsWidth = pad / 2 + 1;
// Now calculate the maximum # of spaces from the left side of the
// screen to the first triangle's level (we will have num-1 steps in the
// triangle)
int spaces = (num - 1) * stepsWidth;
for (int n = 0; n < num; n++) {
// Print the left spaces of the current level, deduct the size of a
// number in each row
if (spaces > 0) {
System.out.printf("%" + spaces + "s", "");
spaces -= stepsWidth;
}
// This will represent the previous combination C(n k-1)
int prevCombination = 1;
for (int k = 1; k <= n + 1; k++) {
System.out.print(prevCombination);
// Calculate how many digits this number has and deduct that to
// the pad between numbers to keep everything aligned
int digits = (int) Math.log10(prevCombination);
if (digits < pad) {
System.out.printf("%" + (pad - digits) + "s", "");
}
// Formula from Wikipedia (we can remove that "+1" if we start
// the row loop at n=1)
prevCombination = prevCombination * (n + 1 - k) / k;
}
// Row separator
System.out.println();
}
}
Hope it helps someone!
This is the question I've been assigned:
A so-called “star number”, s, is a number defined by the formula:
s = 6n(n-1) + 1
where n is the index of the star number.
Thus the first six (i.e. for n = 1, 2, 3, 4, 5 and 6) star numbers are: 1, 13, 37,
73, 121, 181
In contrast a so-called “triangle number”, t, is the sum of the numbers from 1 to n: t = 1 + 2 + … + (n-1) + n.
Thus the first six (i.e. for n = 1, 2, 3, 4, 5 and 6) triangle numbers are: 1, 3, 6, 10, 15, 21
Write a Java application that produces a list of all the values of type int that are both star number and triangle numbers.
When solving this problem you MUST write and use at least one function (such as isTriangeNumber() or isStarNumber()
or determineTriangeNumber() or determineStarNumber()). Also you MUST only use the formulas provided here to solve the problem.
tl;dr: Need to output values that are both Star Numbers and Triangle Numbers.
Unfortunately, I can only get the result to output the value '1' in an endless loop, even though I am incrementing by 1 in the while loop.
public class TriangularStars {
public static void main(String[] args) {
int n=1;
int starNumber = starNumber(n);
int triangleNumber = triangleNumber(n);
while ((starNumber<Integer.MAX_VALUE)&&(n<=Integer.MAX_VALUE))
{
if ((starNumber==triangleNumber)&& (starNumber<Integer.MAX_VALUE))
{
System.out.println(starNumber);
}
n++;
}
}
public static int starNumber( int n)
{
int starNumber;
starNumber= (((6*n)*(n-1))+1);
return starNumber;
}
public static int triangleNumber( int n)
{
int triangleNumber;
triangleNumber =+ n;
return triangleNumber;
}
}
Here's a skeleton. Finish the rest yourself:
Questions to ask yourself:
How do I make a Triangle number?
How do I know if something is a Star number?
Why do I only need to proceed until triangle is negative? How can triangle ever be negative?
Good luck!
public class TriangularStars {
private static final double ERROR = 1e-7;
public static void main(String args[]) {
int triangle = 0;
for (int i = 0; triangle >= 0; i++) {
triangle = determineTriangleNumber(i, triangle);
if (isStarNumber(triangle)) {
System.out.println(triangle);
}
}
}
public static boolean isStarNumber(int possibleStar) {
double test = (possibleStar - 1) / 6.;
int reduce = (int) (test + ERROR);
if (Math.abs(test - reduce) > ERROR)
return false;
int sqrt = (int) (Math.sqrt(reduce) + ERROR);
return reduce == sqrt * (sqrt + 1);
}
public static int determineTriangleNumber(int i, int previous) {
return previous + i;
}
}
Output:
1
253
49141
9533161
1849384153
You need to add new calls to starNumber() and triangleNumber() inside the loop. You get the initial values but never re-call them with the updated n values.
As a first cut, I would put those calls immediatly following the n++, so
n++;
starNumber = starNumber(n);
triangleNumber = triangleNumber(n);
}
}
The question here is that "N" neednt be the same for both star and triangle numbers. So you can increase "n" when computing both star and triangle numbers, rather keep on increasing the triangle number as long as its less the current star number. Essentially you need to maintain two variable "n" and "m".
The first problem is that you only call the starNumber() method once, outside the loop. (And the same with triangleNumber().)
A secondary problem is that unless Integer.MAX_VALUE is a star number, your loop will run forever. The reason being that Java numerical operations overflow silently, so if your next star number would be bigger than Integer.MAX_VALUE, the result would just wrap around. You need to use longs to detect if a number is bigger than Integer.MAX_VALUE.
The third problem is that even if you put all the calls into the loop, it would only display star number/triangle number pairs that share the same n value. You need to have two indices in parallel, one for star number and another for triangle numbers and increment one or the other depending on which function returns the smaller number. So something along these lines:
while( starNumber and triangleNumber are both less than or equal to Integer.MAX_VALUE) {
while( starNumber < triangleNumber ) {
generate next starnumber;
}
while( triangleNumber < starNumber ) {
generate next triangle number;
}
if( starNumber == triangleNumber ) {
we've found a matching pair
}
}
And the fourth problem is that your triangleNumber() method is wrong, I wonder how it even compiles.
I think your methodology is flawed. You won't be able to directly make a method of isStarNumber(n) without, inside that method, testing every possible star number. I would take a slightly different approach: pre-computation.
first, find all the triangle numbers:
List<Integer> tris = new ArrayList<Integer>();
for(int i = 2, t = 1; t > 0; i++) { // loop ends after integer overflow
tris.add(t);
t += i; // compute the next triangle value
}
we can do the same for star numbers:
consider the following -
star(n) = 6*n*(n-1) + 1 = 6n^2 - 6n + 1
therefore, by extension
star(n + 1) = 6*(n+1)*n + 1 = 6n^2 + 6n +1
and, star(n + 1) - star(n - 1), with some algebra, is 12n
star(n+1) = star(n) + 12* n
This leads us to the following formula
List<Integer> stars = new ArrayList<Integer>();
for(int i = 1, s = 1; s > 0; i++) {
stars.add(s);
s += (12 * i);
}
The real question is... do we really need to search every number? The answer is no! We only need to search numbers that are actually one or the other. So we could easily use the numbers in the stars (18k of them) and find the ones of those that are also tris!
for(Integer star : stars) {
if(tris.contains(star))
System.out.println("Awesome! " + star + " is both star and tri!");
}
I hope this makes sense to you. For your own sake, don't blindly move these snippets into your code. Instead, learn why it does what it does, ask questions where you're not sure. (Hopefully this isn't due in two hours!)
And good luck with this assignment.
Here's something awesome that will return the first 4 but not the last one. I don't know why the last won't come out. Have fun with this :
class StarAndTri2 {
public static void main(String...args) {
final double q2 = Math.sqrt(2);
out(1);
int a = 1;
for(int i = 1; a > 0; i++) {
a += (12 * i);
if(x((int)(Math.sqrt(a)*q2))==a)out(a);
}
}
static int x(int q) { return (q*(q+1))/2; }
static void out(int i) {System.out.println("found: " + i);}
}