Another Google question - drop glassballs from a building 2 博客分类: algorithms GoogleJ#RESTjunitUP
程序员文章站
2024-03-07 12:00:03
...
Here is the code following the logic from the previous post:
The generateSumArrays() does the forward sum-ups, e.g., (1), (2), ..., this is the main functionality. There is also a floors field that holds the results from backward sum-ups, (A), (B), .... However, this field is not really used in computation, because the
starting point is dynamic, not fixed like in this field. So this is merely for information and debug. A similar method to
compute this backward sum is in another class.
Another functionality of this class is to answer the questions posted in the above Chinese paragraph. For a given height of the build, i.e., the number of floors is fixed, how many balls are optimal, e.g., if we are given a building with 10 floors, 50 balls won't reduce the minimal trials, in fact maybe it takes the same number of trials as 10 balls. These are in the first 3 methods. The basic logic is that since the worst case trials are evenly distributed, we just find one worst path of floors to count the trials.
The test cases is
The method test4Balls() prints out the optimal number which are verified by test5Balls() and test6Balls().
java 代码
- package glassball;
- import java.util.List;
- import java.util.ArrayList;
- /**
- * Google interview question
- */
- public class GlassBallPuzzle
- {
- // first index is on glassballs, second is on sum.
- // The sum is used to compare with the total floors of the building and
- // then determine the last element in the previous sum, which is used
- // as the starting point of the floor array.
- private int[][] recursiveSums;
- // the top selection of floors to try. This is not essential, but
- // helpful for testing.
- private int[][] floors;
- private int numOfGlassballs;
- private int numOfFloors;
- public GlassBallPuzzle(int numOfGlassballs, int numOfFloors)
- {
- this.numOfGlassballs = numOfGlassballs;
- this.numOfFloors = numOfFloors;
- generateSumArrays();
- generateFloorArrays();
- }
- public int getMinimalTrials()
- {
- // since all worst paths should have the same number, we pick up any
- // worst path and should have the same number of trials. This path
- // has the broken floor at level 1.
- int len = recursiveSums[numOfGlassballs - 1].length;
- int minimalTrials = recursiveSums[0][len-1] - 1;
- // add trials.
- minimalTrials += getTrials(numOfGlassballs, len);
- return minimalTrials;
- }
- public int[] getOptimalTrialsAndBalls()
- {
- int minimalTrials = numOfFloors;
- int minimalBalls = numOfGlassballs;
- for (int nballs=1; nballs<=numOfGlassballs; nballs++)
- {
- int len = recursiveSums[nballs - 1].length;
- int newTrials = recursiveSums[0][len-1] - 1;
- // add trials.
- newTrials += getTrials(nballs, len);
- if (newTrials < minimalTrials)
- {
- minimalTrials = newTrials;
- minimalBalls = nballs;
- }
- }
- return new int[] { minimalTrials, minimalBalls};
- }
- private int getTrials(int balls, int index)
- {
- // to move across the arrays for balls.
- int ret=0;
- //
- for (int i=0; i<balls; i++)
- {
- // otherwise, there is no need to try.
- if (recursiveSums[i][index-1] < numOfFloors)
- ret++;
- }
- return ret;
- }
- public int[][] getRecursiveSums() { return recursiveSums; }
- private void generateSumArrays()
- {
- recursiveSums = new int[numOfGlassballs][];
- // initialize the first array with 1, 2, 3, 4, ...
- recursiveSums[0] = new int[this.numOfFloors];
- for (int j=0; j<numOfFloors; j++)
- {
- recursiveSums[0][j] = j + 1;
- }
- // now recursively generate the rest of arrays by summation
- for (int i=1; i<numOfGlassballs; i++)
- {
- // since the size is unknown, so we use a list.
- List sums = new ArrayList();
- for (int j=0; j<numOfFloors; j++)
- {
- int total = 0;
- for (int k=0; k<=j; k++) total += recursiveSums[i-1][k];
- sums.add(new Integer(total));
- if (total >= numOfFloors) break;
- }
- recursiveSums[i] = new int[sums.size()];
- for (int j=0; j<sums.size(); j++)
- {
- recursiveSums[i][j] = ((Integer)sums.get(j)).intValue();
- }
- }
- }
- private void generateFloorArrays()
- {
- floors = new int[numOfGlassballs][];
- // If there is one ball, we have to start from floor 1, 2, etc.
- floors[0] = recursiveSums[0];
- // The floors starts from the end of sums series.
- for (int i=1; i<numOfGlassballs; i++)
- {
- floors[i] = new int[recursiveSums[i].length];
- int total=0;
- for (int j=0; j<recursiveSums[i].length; j++)
- {
- total += recursiveSums[i-1][recursiveSums[i].length - 1 - j];
- floors[i][j] = total;
- }
- }
- }
- // could be moved to somewhere else.
- public void printAllResults()
- {
- for (int i=0; i<numOfGlassballs; i++)
- {
- printIntermediateSteps(i);
- }
- }
- private void printIntermediateSteps(int ballIndex)
- {
- System.out.print("sum series for " + (ballIndex + 1) + " balls=");
- int[] segments = recursiveSums[ballIndex];
- for (int i=0; i<segments.length; i++)
- {
- System.out.print(segments[i] + ", ");
- }
- System.out.println();
- System.out.print("floors series for " + (ballIndex + 1) + " balls=");
- segments = floors[ballIndex];
- for (int i=0; i<segments.length; i++)
- {
- System.out.print(segments[i] + ", ");
- }
- System.out.println();
- }
- }
The generateSumArrays() does the forward sum-ups, e.g., (1), (2), ..., this is the main functionality. There is also a floors field that holds the results from backward sum-ups, (A), (B), .... However, this field is not really used in computation, because the
starting point is dynamic, not fixed like in this field. So this is merely for information and debug. A similar method to
compute this backward sum is in another class.
Another functionality of this class is to answer the questions posted in the above Chinese paragraph. For a given height of the build, i.e., the number of floors is fixed, how many balls are optimal, e.g., if we are given a building with 10 floors, 50 balls won't reduce the minimal trials, in fact maybe it takes the same number of trials as 10 balls. These are in the first 3 methods. The basic logic is that since the worst case trials are evenly distributed, we just find one worst path of floors to count the trials.
The test cases is
java 代码
- package glassball;
- import junit.framework.TestCase;
- /**
- * Testcases for minimal trials.
- */
- public class GlassBallPuzzleTest extends TestCase
- {
- public void test2Balls()
- {
- GlassBallPuzzle puzzle = new GlassBallPuzzle(2, 100);
- puzzle.printAllResults();
- System.out.println("minimal trials=" + puzzle.getMinimalTrials());
- assertTrue(puzzle.getMinimalTrials() == 14);
- }
- public void test3Balls()
- {
- GlassBallPuzzle puzzle = new GlassBallPuzzle(3, 100);
- puzzle.printAllResults();
- System.out.println("minimal trials=" + puzzle.getMinimalTrials());
- assertTrue(puzzle.getMinimalTrials() == 9);
- }
- public void test4Balls()
- {
- GlassBallPuzzle puzzle = new GlassBallPuzzle(4, 100);
- puzzle.printAllResults();
- System.out.println("minimal trials=" + puzzle.getMinimalTrials());
- assertTrue(puzzle.getMinimalTrials() == 8);
- int[] optimals = puzzle.getOptimalTrialsAndBalls();
- System.out.println("optimal trials and balls=" + optimals[0] + ", " + optimals[1]);
- }
- public void test5Balls()
- {
- GlassBallPuzzle puzzle = new GlassBallPuzzle(5, 100);
- puzzle.printAllResults();
- System.out.println("minimal trials=" + puzzle.getMinimalTrials());
- assertTrue(puzzle.getMinimalTrials() == 8);
- }
- public void test6Balls()
- {
- GlassBallPuzzle puzzle = new GlassBallPuzzle(6, 100);
- puzzle.printAllResults();
- System.out.println("minimal trials=" + puzzle.getMinimalTrials());
- assertTrue(puzzle.getMinimalTrials() == 8);
- }
- public void test50Balls()
- {
- GlassBallPuzzle puzzle = new GlassBallPuzzle(50, 200);
- puzzle.printAllResults();
- System.out.println("minimal trials=" + puzzle.getMinimalTrials());
- assertTrue(puzzle.getMinimalTrials() == 20);
- }
- }
The method test4Balls() prints out the optimal number which are verified by test5Balls() and test6Balls().