I am working on this problem to find the smallest triplet given a set of triplets which is smallest in all three dimensions. However, if there exists a triplet which is smallest is any one or two dimensions than the smallest across all three dimensions, that too needs to be considered.
Example
Let me give an example.
Say, my triplets are as follows
(25, 30, 34), (15, 31, 21), (10, 40, 21), (50, 30, 34), (25, 30, 10), (9, 20, 15)
Now, (9,20,15) looks to be the smallest across all three dimensions. However, there also exists an option (25,30,10) which is smallest in the third dimension since it's score in the third diemnsion(10) is smallest than any of the other options, so that too needs to be included in the output too. so the final output would be {(9,20,15) and (25,30,10)}
So, basically a solution should be considered if it is either Dominant or Optimal. I can define these as follows
1. Dominant : If an outcome o is at least as good for another agent as another outcome o' and there is some
agent who strictly prefers o to o'. Then o pareto-dominates o'
2. Optimal : o* is pareto-optimal if it isn't pareto-dominated by anything else
My algorithm
This is my algorithm. Please see the attached code. Let the three dimensions be called Course1Score, Course2Score and Course3Score.
So I traverse across the inputs, and find the smallest for each of the following
1.{Course1Score}
2.{Course2Score}
3.{Course3Score}
4.{Course1Score, Course2Score}
5.{Course1Score, Course3Score}
6.{Course2Score, Course3Score}
7.{Course1Score, Course2Score, Course3Score}
I then find the distinct solution among the solutions which minimize the above objectives.
False case
Now this would work for most cases except in a case like below. Let the input be (1,100,100), (100,1,100), (100,100,1), (1,1,1)
As per the above algorithm, the scores which minimize the above objectives would be as follows
1.Minimize {Course1Score} - (1,100,100)
(remember this won't be over-written by say,(1,1,1) since Course1Score of (1,1,1) IS NOT LESS than Course1Score of (1,100,100) which comes first in the order of inputs) )
2.Minimize {Course2Score} - (100,1,100)
3.Minimize {Course3Score} - (100,100,1)
4.Minimize {Course1Score, Course2Score} - (1,100,100)
5.Minimize {Course1Score, Course3Score} - (1,100,100)
6.Minimize {Course2Score, Course3Score} - (100,1,100)
7.Minimize {Course1Score, Course2Score, Course3Score} - (1,1,1)
Continuing with the algorithm, we find the distinct solution and report them as (1,100,100), (100,1,100), (100,100,1), (1,1,1)
However, this solution is incorrect. Since (1,1,1) beats all of the other solutions in all three dimensions, and none of (1,100,100), (100,1,100), (100,100,1) are better than (1,1,1) in any of the dimensions. So, I add an extra condition to check this at the end which can be found in the function
Online java fiddle
This is an online java fiddle of my implementation
My implementation
Please find my code
import java.util.ArrayList;
/* Glossary
* 1. Dominant : If an outcome o is at least as good for another agent as another outcome o' and there is some
* agent who strictly prefers o to o'. Then o Triplet-dominates o'
*
* 2. Optimal : o* is Triplet-optimal if it isn't Triplet-dominated by anything else
*
* */
public class HelloWorld
{
public static void main(String[] args)
{
Triplet myTriplet = new Triplet();
/* Populating input and printing them */
System.out.println("Printing input");
myTriplet.PopulateSampleInput();
myTriplet.Print(myTriplet.options);
/* Printing the Triplet-Optimal solutions */
ArrayList<Option> TripletSolutions = myTriplet.FindTripletOptimalSolutions();
System.out.println("Printing TripletSolutions : ");
myTriplet.Print(TripletSolutions);
}
}
class Triplet
{
ArrayList<Option> options;
public Triplet()
{
options = new ArrayList<Option>();
}
void PopulateSampleInput()
{
Option option1 = new Option(25, 30, 34);
Option option2 = new Option(15, 31, 21);
Option option3 = new Option(10, 40, 21);
Option option4 = new Option(50, 30, 34);
Option option5 = new Option(25, 30, 10);
Option option6 = new Option(9, 20, 15);
options.add(option1);
options.add(option2);
options.add(option3);
options.add(option4);
options.add(option5);
options.add(option6);
}
void Print(ArrayList<Option> al)
{
for(int i = 0;i< al.size();i++)
{
System.out.println(al.get(i).Course1Score + "," + al.get(i).Course2Score + "," + al.get(i).Course3Score);
}
}
ArrayList<Option> FindTripletOptimalSolutions()
{
Option[] map = new Option[7];
/* Initialization : Initially the best solution for minimizing all objectives is the first solution */
for(int i = 0;i<map.length;i++)
map[i] = options.get(0);
for(int i=1;i<options.size();i++)
{
/* Fixing {1} */
if(options.get(i).Course1Score < map[0].Course1Score)
map[0] = options.get(i);
/* Fixing {2} */
if(options.get(i).Course2Score < map[1].Course2Score)
map[1] = options.get(i);
/* Fixing {3} */
if(options.get(i).Course3Score < map[2].Course3Score)
map[2] = options.get(i);
/* Fixing {1,2} */
if(options.get(i).Course1Score <= map[3].Course1Score && options.get(i).Course2Score <= map[3].Course2Score)
map[3] = options.get(i);
/* Fixing {1,3} */
if(options.get(i).Course1Score <= map[4].Course1Score && options.get(i).Course3Score <= map[4].Course3Score)
map[4] = options.get(i);
/* Fixing {2,3} */
if(options.get(i).Course2Score <= map[5].Course2Score && options.get(i).Course3Score <= map[5].Course3Score)
map[5] = options.get(i);
/* Fixing {1,2,3} */
if(options.get(i).Course1Score <= map[6].Course1Score && options.get(i).Course2Score <= map[6].Course2Score && options.get(i).Course3Score <= map[6].Course3Score)
map[6] = options.get(i);
}
/* find unique solutions */
ArrayList<Option> DistinctSolutions = new ArrayList<Option>();
DistinctSolutions = findUnique(map);
/* keeping only solutions that add something new */
ArrayList<Option> TripletSolutions = EliminateWeakSolutionInCaseOfTie(DistinctSolutions);
return TripletSolutions;
}
/* This function returns the unique solutions, otherwise, they will cancel out each other inside the
* EliminateWeakSolutionInCaseOfTie function that comes next */
ArrayList<Option> findUnique(Option[] map)
{
ArrayList<Option> TripletSolutions = new ArrayList<Option>();
for(int i = 0;i<map.length;i++)
{
if(!TripletSolutions.contains(map[i]))
TripletSolutions.add(map[i]);
}
return TripletSolutions;
}
/* This function in case of ties where map[0]'s Course1Score is only equal to, but not less than
* map[6]'s Course1Score, which in addition to minimizing Course1Score, also minimizes
* Course2Score and Course3Score */
ArrayList<Option> EliminateWeakSolutionInCaseOfTie(ArrayList<Option> DistinctSolutions)
{
ArrayList<Option> TripletSolutions = new ArrayList<Option>();
int Include = 1;
for(int i = 0;i<DistinctSolutions.size();i++,Include=1)
{
for(int j = 0;j<DistinctSolutions.size();j++)
{
if(i!=j && DistinctSolutions.get(j).Course1Score <= DistinctSolutions.get(i).Course1Score && DistinctSolutions.get(j).Course2Score <= DistinctSolutions.get(i).Course2Score && DistinctSolutions.get(j).Course3Score <= DistinctSolutions.get(i).Course3Score)
{
Include = 0;
break;
}
}
if(Include == 1)
TripletSolutions.add(DistinctSolutions.get(i));
}
return TripletSolutions;
}
}
class Option
{
int Course1Score;
int Course2Score;
int Course3Score;
public Option(int Course1Score, int Course2Score, int Course3Score)
{
// TODO Auto-generated constructor stub
this.Course1Score = Course1Score;
this.Course2Score = Course2Score;
this.Course3Score = Course3Score;
}
}
Can you please suggest an algorithm for the above, and/or review my algo and implementation?
EDIT : I think this solution works
Pseudocode
ParetoSolutionPool[1] = input[1]
for(i in 2:input)
boolean ParetoDominant = false;
boolean ParetoOptimal = true;
for(j in 1:ParetoSolutionPool)
if(input[i] ParetoDominates ParetoSolutionPool[j])
remove ParetoSolutionPool[j]
ParetoDominant = true;
if(input[i] IsParetoDominatedBy ParetoSolutionPool[j])//extra if(ParetoDominant == false && ParetoOptimal == true && above)
ParetoOptimal = false;
end of for loop over j
if(ParetoDominant || ParetoOptimal == true)
add input[i] to ParetoSolutionPool
end of for loop over i
Pseudocode in words
Basically, two checks.
1.If an input/option domoinates(lower in all three dimensions), one of the existing solutions, that "existing solution" is popped, and replaced by this input, since it's better unanimously. (Eg 25,30,10 better than 25,30,34)
2.If an input is NOT WORSE (in all three dimensions )than any of the existing solutions, then it too has to be considered to the solution pool.
So basically in either of the two cases, above, an input is added to the solution pool. Only difference between the two being that in the first case, the weaker existing solution is popped as well.
Code
package TripletOptimizationAlgorithms;
import java.io.BufferedReader;
import java.io.DataInputStream;
import java.io.FileInputStream;
import java.io.InputStreamReader;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.Collections;
public class algo4
{
public static void main(String[] args)
{
Triplet myTriplet = new Triplet();
/* Populating input and printing them */
System.out.println("Printing input");
//myTriplet.PopulateSampleInput();
myTriplet.PopulateSampleInputFromFile();
myTriplet.Print(myTriplet.options);
System.out.println("Number of inputs read=="+myTriplet.options.size());
/* Printing the Triplet-Optimal solutions */
final long startTime = System.currentTimeMillis();
ArrayList<Option> TripletSolutions = myTriplet.FindTripletOptimalSolutions();
final long endTime = System.currentTimeMillis();
System.out.println("Printing TripletSolutions : ");
myTriplet.Print(TripletSolutions);
System.out.println("Total execution time: " + (endTime - startTime) + " milliseconds" );
}
}
class Triplet
{
ArrayList<Option> options;
public Triplet()
{
options = new ArrayList<Option>();
}
void PopulateSampleInput()
{
Option option1 = new Option(25, 30, 34);
Option option2 = new Option(15, 31, 21);
Option option3 = new Option(10, 40, 21);
Option option4 = new Option(30, 30, 34);
Option option5 = new Option(25, 30, 10);
Option option6 = new Option(9, 20, 15);
options.add(option1);
options.add(option2);
options.add(option3);
options.add(option4);
options.add(option5);
options.add(option6);
}
void PopulateSampleInputFromFile()
{
try
{
String pwd = Paths.get(".").toAbsolutePath().normalize().toString();
String inputpath = pwd + "/src/TripletOptimizationAlgorithms/myinput.txt";
FileInputStream fstream = new FileInputStream(inputpath);
DataInputStream in = new DataInputStream(fstream);
BufferedReader br = new BufferedReader(new InputStreamReader(in));
String strLine;
while ((strLine = br.readLine()) != null)
{
String[] tokens = strLine.split(" ");
Option myoption = new Option(Integer.parseInt(tokens[0]),Integer.parseInt(tokens[1]),Integer.parseInt(tokens[2]));//process record , etc
options.add(myoption);
}
in.close();
}
catch (Exception e)
{
System.err.println("Error: " + e.getMessage());
}
}
void Print(ArrayList<Option> al)
{
for(int i = 0;i< al.size();i++)
{
System.out.println(al.get(i).Course1Score + "," + al.get(i).Course2Score + "," + al.get(i).Course3Score);
}
}
ArrayList<Option> FindTripletOptimalSolutions()
{
/* Initialization : Initialize the TripletSolutions to be the first option */
ArrayList<Option> TripletSolutions = new ArrayList<Option>();
TripletSolutions.add(options.get(0));
/* looping across input */
for(int i = 1;i<options.size();i++)
{
boolean TripletDominant = false;
boolean TripletOptimal = true;
Option optionUnderCheck = options.get(i);
ArrayList<Integer> IndicesToRemove = new ArrayList<Integer>();
/* looping across TripletSolutions */
for(int j = 0;j<TripletSolutions.size();j++)
{
if(isTripletDominant(optionUnderCheck, TripletSolutions.get(j)) == true)
{
TripletDominant = true;
IndicesToRemove.add(j);
}
if(IsTripletDominatedBy(optionUnderCheck, TripletSolutions.get(j)) == true)
{
TripletOptimal = false;
}
}
/* the weaker solutions have to be removed */
if(TripletDominant == true)
{
Collections.sort(IndicesToRemove, Collections.reverseOrder());
for(int k = 0;k<IndicesToRemove.size();k++)
{
TripletSolutions.remove(IndicesToRemove.get(k).intValue());
}
}
if(TripletDominant == true || TripletOptimal == true)
TripletSolutions.add(optionUnderCheck);
}
return TripletSolutions;
}
boolean isTripletDominant(Option optionUnderCheck, Option existingSolution)
{
if(optionUnderCheck.Course1Score <= existingSolution.Course1Score && optionUnderCheck.Course2Score <= existingSolution.Course2Score && optionUnderCheck.Course3Score <= existingSolution.Course3Score)
return true;
return false;
}
boolean IsTripletDominatedBy(Option optionUnderCheck, Option existingSolution)
{
if(optionUnderCheck.Course1Score >= existingSolution.Course1Score && optionUnderCheck.Course2Score >= existingSolution.Course2Score && optionUnderCheck.Course3Score >= existingSolution.Course3Score)
return true;
return false;
}
}
class Option
{
int Course1Score;
int Course2Score;
int Course3Score;
public Option(int Course1Score, int Course2Score, int Course3Score)
{
// TODO Auto-generated constructor stub
this.Course1Score = Course1Score;
this.Course2Score = Course2Score;
this.Course3Score = Course3Score;
}
}
Actually this can be simplified quite a lot.
So let's take a look at your rules for what are matches:
{Course1Score} is minimal
{Course2Score} ...
{Course3Score} ...
{Course1Score, Course2Score} optimal or dominant solution
{Course1Score, Course3Score} ...
{Course2Score, Course3Score} ...
{Course1Score, Course2Score, Course3Score} ...
Rules 1,2 and 3 simply search for the value that minimizes CourseNScore (replace N with the rule-number). 4,5 and 6 search for pairs (a , b) (with a and b replaced by the respective CourseScore), such that there exists no pair with a lower a or b. These pairs will as well be found by Rules 1 - 3, no matter whether they are dominant or optimal. Same applies for rule 7 with rules 4 - 6.
Thus we can easily reduce the search to finding the tuples where 1 element is minimal and reduce the set of matches. This will speedup the search quite a bit. This will result in 3 Sets of tuples (one for each element of the tuples that is searched).
Next step:
Reduce the set of found tuples. This can be done in a pretty naive approach:
A solution that matches Rule 7 must be in all sets generated by the search. A solution that matches Rule 4 must be in the sets that match Rule 1 and 2.
The reduction of the results thus becomes a pretty trivial task.
For the review:
Variable- and Method-names are usually lowercase in java.
The part of generating a String from Option, like used in Triplet.Print should be transferred to Option.toString(), since that's the usual way. But there's not much to criticize with this code.
Related
Question:
In this problem, the scenario we are evaluating is the following: You're standing at the base of a staircase and are heading to the top. A small stride will move up one stair, and a large stride advances two. You want to count the number of ways to climb the entire staircase based on different combinations of large and small strides. For example, a staircase of three steps can be climbed in three different ways: three small strides, one small stride followed by one large stride, or one large followed by one small.
The call of waysToClimb(3) should produce the following output:
1 1 1,
1 2,
2 1
My code:
public static void waysToClimb(int n){
if(n == 0)
System.out.print("");
else if(n == 1)
System.out.print("1");
else {
System.out.print("1 ");
waysToClimb(n - 1);
System.out.print(",");
System.out.print("2 ");
waysToClimb(n - 2);
}
}
My output:
1 1 1,
2,
2 1
My recursion doesn't seem to remember the path it took any idea how to fix it?
Edit:
Thank you guys for the responses. Sorry for the late reply
I figured it out
public static void waysToClimb(int n){
String s ="[";
int p=0;
com(s,p,n);
}
public static void com(String s,int p,int n){
if(n==0 && p==2)
System.out.print(s.substring(0,s.length()-2)+"]");
else if(n==0 && p !=0)
System.out.print(s+"");
else if(n==0 && p==0)
System.out.print("");
else if(n==1)
System.out.print(s+"1]");
else {
com(s+"1, ",1,n-1);
System.out.println();
com(s+"2, ",2,n-2);
}
}
If you explicity want to print all paths (different than counting them or finding a specific one), you need to store them all the way down to 0.
public static void waysToClimb(int n, List<Integer> path)
{
if (n == 0)
{
// print whole path
for (Integer i: path)
{
System.out.print(i + " ");
}
System.out.println();
}
else if (n == 1)
{
List<Integer> newPath = new ArrayList<Integer>(path);
newPath.add(1);
waysToClimb(n-1, newPath);
}
else if (n > 1)
{
List<Integer> newPath1 = new ArrayList<Integer>(path);
newPath1.add(1);
waysToClimb(n-1, newPath1);
List<Integer> newPath2 = new ArrayList<Integer>(path);
newPath2.add(2);
waysToClimb(n-2, newPath2);
}
}
initial call: waysToClimb(5, new ArrayList<Integer>());
Below mentioned solution will work similar to Depth First Search, it will explore one path. Once a path is completed, it will backtrace and explore other paths:
public class Demo {
private static LinkedList<Integer> ll = new LinkedList<Integer>(){{ add(1);add(2);}};
public static void main(String args[]) {
waysToClimb(4, "");
}
public static void waysToClimb(int n, String res) {
if (ll.peek() > n)
System.out.println(res);
else {
for (Integer elem : ll) {
if(n-elem >= 0)
waysToClimb(n - elem, res + String.valueOf(elem) + " ");
}
}
}
}
public class Test2 {
public int climbStairs(int n) {
// List of lists to store all the combinations
List<List<Integer>> ans = new ArrayList<List<Integer>>();
// initially, sending in an empty list that will store the first combination
csHelper(n, new ArrayList<Integer>(), ans);
// a helper method to print list of lists
print2dList(ans);
return ans.size();
}
private void csHelper(int n, List<Integer> l, List<List<Integer>> ans) {
// if there are no more stairs to climb, add the current combination to ans list
if(n == 0) {
ans.add(new ArrayList<Integer>(l));
}
// a necessary check that prevent user at (n-1)th stair to climb using 2 stairs
if(n < 0) {
return;
}
int currStep = 0;
// i varies from 1 to 2 as we have 2 choices i.e. to either climb using 1 or 2 steps
for(int i = 1; i <= 2; i++) {
// climbing using step 1 when i = 1 and using 2 when i = 2
currStep += 1;
// adding current step to the arraylist(check parameter of this method)
l.add(currStep);
// make a recursive call with less number of stairs left to climb
csHelper(n - currStep, l, ans);
l.remove(l.size() - 1);
}
}
private void print2dList(List<List<Integer>> ans) {
for (int i = 0; i < ans.size(); i++) {
for (int j = 0; j < ans.get(i).size(); j++) {
System.out.print(ans.get(i).get(j) + " ");
}
System.out.println();
}
}
public static void main(String[] args) {
Test2 t = new Test2();
t.climbStairs(3);
}
}
Please note this solution will timeout for larger inputs as this isn't a memoized recursive solution and can throw MLE(as I create a new list when a combination is found).
Hope this helps.
if anyone looking for a python solution, for this problem.
def way_to_climb(n, path=None, val=None):
path = [] if path is None else path
val = [] if val is None else val
if n==0:
val.append(path)
elif n==1:
new_path = path.copy()
new_path.append(1)
way_to_climb(n-1, new_path, val)
elif n>1:
new_path1 = path.copy()
new_path1.append(1)
way_to_climb(n-1, new_path1, val)
new_path2 = path.copy()
new_path2.append(2)
way_to_climb(n-2, new_path2, val)
return val
Note: it is based on the #unlut solution, here OP has used a top-down recursive approach. This solution is for all people who looking for all combination of staircase problem in python, no python question for this so i have added a python solution here
if we use a bottom-up approach and use memorization, then we can solve the problem faster.
Even though you did find the correct answer to the problem with your code, you can still improve upon it by using just one if to check if the steps left is 0. I used a switch to check the amount of steps taken because there are only 3 options, 0, 1, or 2. I also renamed the variables that were used to make the code more understandable to anyone seeing it for the first time, as it is quite confusing if you are just using one letter variable names. Even with all these changes the codes run the same, I just thought it might be better to add some of these things for others who might view this question in the future.
public static void climbStairsHelper(String pathStr, int stepsTaken, int stepsLeft)
{
if(stepsLeft == 0)
{
switch(stepsTaken)
{
case 2:
System.out.print(pathStr.substring(0, pathStr.length() - 2) + "]");
break;
case 1:
System.out.print(pathStr + "");
break;
case 0:
System.out.print("");
break;
}
}
else if(stepsLeft == 1)
{
System.out.print(pathStr + "1]");
}
else
{
climbStairsHelper(pathStr + "1, ", 1, stepsLeft - 1);
System.out.println();
climbStairsHelper(pathStr + "2, ", 2, stepsLeft - 2);
}
}`
`
Perhaps i wasn't clear enough. I apologize. I tried condensing and adding images in this edit to make it more clear.
50 Seed Value, 1200 RNG Value.
60 Seed Value, 1200 RNG Value.
In the examples above (for clarity instead of writing it all out), you can see the outputs you get for 50 vs 60. It's not the distinct values I'm concerned. It's the display now. As you can see, the number gets bigger since I put in a new seed value. I want it to display what the 50 seed value is, but have the properties of whatever seed value I put in.
If I put in for example 60, I want to get:
H1 T1 H1 T1 HHH3 TTTTT5 H1 T1 HHHH4 T1 HH2 T1 H1 T1 H1 T1 H1 T1 H1 TTT3 H1 TTT3 H1 TTTT4 H1 T1 HHH3 TT2 H1 T... (just like with the 50 seed value).
BUT it would get 35 distinct values instead of the 30. Let me know if I can be clearer I apologize for being so confusing.
import java.util.Scanner;
import java.util.Random;
public class CoinFlipAnalyzer{
private static final Scanner
stdIn = new Scanner(System.in);
public static void main (String[] args){
// Integer Values:
int totalNumberOfRuns = 0;
int run = 1;
// Boolean Values:
boolean theCoin;
boolean tempVal = false;
// Gathering the Users Input:
System.out.println("Welcome to the coin flip analyzer.\n"
+ "How many flips?");
int numberOfFlips = stdIn.nextInt();
System.out.println("What do you want to seed the random number generator with?");
int rngSeed = stdIn.nextInt();
Random rng = new Random(rngSeed); // Initiates the Random Number Generator.
System.out.println();
// Loop and Array to Decide Whether the Value is Heads or Tail.
long[] runLength = new long[numberOfFlips];
for (int i = 0; i < numberOfFlips; i++) {
theCoin = rng.nextBoolean(); // As requested, I used the nextBoolean expression.
if (theCoin != tempVal) {
if (i > 0) {
System.out.print(run + " ");
}
runLength[run - 1]++;
totalNumberOfRuns++;
run = 1;
}
else {
run++;
}
if (theCoin) {
System.out.print("H");
tempVal = true;
}
else {
System.out.print("T");
tempVal = false;
}
}
System.out.print("...");
System.out.println();
System.out.println("There were a total of " + totalNumberOfRuns +
" distinct runs in the simulation.\nTheir breakdown follows:");
System.out.println();
I think I understand the requirement. In essence, there is some desired width, and if the number of outputs exceeds the width, then print using an ellipses.
There is the StringUtils from Apache Commons that has an 'Abbreviate' method.
public static String abbreviate(String str,
int maxWidth)
Abbreviates a String using ellipses. This will turn "Now is the time for all good men" into "Now is the time for..."
To use this (or the other suggestion below), I would remove the immediate output that is being generated in the run, and instead build a String. One could build a char[] as well, but here we will go with a String (or a StringBuilder). There is another advantage to so doing -- it is generally a good practice to separate some of the logic from the output. Plus it would be more testable.
So, if one can use the StringUtils.abbreviate(...), then take the result from the doFlips(...) and pass it to the method, and the result will be done.
/*
* moved the flipping into a method; allow it to build the
* results rather than immediately outputting them
*/
private static StringBuilder doFlips(int numberOfFlips, Random rng)
{
long[] runLength = new long[numberOfFlips];
boolean theCoin;
boolean tempVal = false;
int run = 1;
int totalNumberOfRuns = 0;
// Here we will collect the output; use better name in production
StringBuilder sb = new StringBuilder();
for (int i = 0; i < numberOfFlips; i++) {
theCoin = rng.nextBoolean(); // As requested, I used the nextBoolean
// expression.
if (theCoin != tempVal) {
if (i > 0) {
sb.append(run);
sb.append(" ");
}
runLength[run - 1]++;
totalNumberOfRuns++;
run = 1;
}
else {
run++;
}
if (theCoin) {
sb.append("H");
tempVal = true;
}
else {
sb.append("T");
tempVal = false;
}
}
return sb;
}
If one cannot use the library, it is easy enough to write a chop method:
/**
* Chop the input StringBuilder and give "..." at
* maxOutput.
*
* NOTE: no error checking
*/
private static String ourChop(StringBuilder sb, int maxOutput)
{
if (sb.length() <= maxOutput) {
return sb.toString();
}
// we chop everything past maxOutput - 3
sb.setLength(maxOutput - 3);
sb.append("...");
return sb.toString();
}
So, we can then do the following:
public static void main(String[] args)
{
int seed = 1200;
int maxOutput = 25;
// 50 flips, 25 length max, including ... if needed
StringBuilder res = doFlips(50, new Random(seed));
System.out.println(ourChop(res, maxOutput));
res = doFlips(60, new Random(seed));
System.out.println(ourChop(res, maxOutput));
And we get this output (at 25):
H1 T1 H1 T1 HHH3 TTTTT...
H1 T1 H1 T1 HHH3 TTTTT...
Now, if the goal is to align to the max output of some given run, then one would need to collect all of the runs (50, 60, etc.), and then find the particular value (say the shortest of the outputs; note that in theory in a truly random setting, 60 could have a shorter output than 50, but not when using the same seed). One could then use that determined value to chop to a given output length.
If I have misunderstood the approach, I apologize.
I want to generate a unique random index everyday to show "word of the day" from N number of words in a list.
Until every words are indexed from a list, I dont't want the same index to be repeated. For example, I have N words in a list; the index each day should be different for N days.
If you really can't be bothered to keep a record of the numbers you've already used you could use a rather nice mechanism known as a Linear Feedback Shift Register or LFSR. This Generates a random (but predictable, if you know it's an LFSR) sequence of numbers spanning all numbers of n bits.
Just choose n to be greater than your 'N' and throw away any numbers too big.
/**
* Linear feedback shift register
*
* Taps can be found at: See http://www.xilinx.com/support/documentation/application_notes/xapp052.pdf See http://mathoverflow.net/questions/46961/how-are-taps-proven-to-work-for-lfsrs/46983#46983 See
* http://www.newwaveinstruments.com/resources/articles/m_sequence_linear_feedback_shift_register_lfsr.htm See http://www.yikes.com/~ptolemy/lfsr_web/index.htm See
* http://seanerikoconnor.freeservers.com/Mathematics/AbstractAlgebra/PrimitivePolynomials/overview.html
*
* #author OldCurmudgeon
*/
public class LFSR implements Iterable<BigInteger> {
// Bit pattern for taps.
private final BigInteger taps;
// Where to start (and end).
private final BigInteger start;
// The poly must be primitive to span the full sequence.
public LFSR(BigInteger primitivePoly, BigInteger start) {
// Where to start from (and stop).
this.start = start.equals(BigInteger.ZERO) ? BigInteger.ONE : start;
// Knock off the 2^0 coefficient of the polynomial for the TAP.
this.taps = primitivePoly.shiftRight(1);
}
#Override
public Iterator<BigInteger> iterator() {
return new LFSRIterator(start);
}
private class LFSRIterator implements Iterator<BigInteger> {
// The last one we returned.
private BigInteger last = null;
// The next one to return.
private BigInteger next = null;
public LFSRIterator(BigInteger start) {
// Do not return the seed.
last = start;
}
#Override
public boolean hasNext() {
if (next == null) {
/*
* Uses the Galois form.
*
* Shift last right one.
*
* If the bit shifted out was a 1 - xor with the tap mask.
*/
boolean shiftedOutA1 = last.testBit(0);
// Shift right.
next = last.shiftRight(1);
if (shiftedOutA1) {
// Tap!
next = next.xor(taps);
}
// Never give them `start` again.
if (next.equals(start)) {
// Could set a finished flag here too.
next = null;
}
}
return next != null;
}
#Override
public BigInteger next() {
// Remember this one.
last = hasNext() ? next : null;
// Don't deliver it again.
next = null;
return last;
}
#Override
public void remove() {
throw new UnsupportedOperationException("Not supported.");
}
#Override
public String toString() {
return LFSR.this.toString()
+ "[" + (last != null ? last.toString(16) : "")
+ "-" + (next != null ? next.toString(16) : "") + "]";
}
}
#Override
public String toString() {
return "(" + taps.toString(32) + ")-" + start.toString(32);
}
public static void main(String args[]) {
try {
new LFSRTest().test();
} catch (Throwable t) {
t.printStackTrace(System.err);
}
}
}
class LFSRTest {
public void test(int[] tap, int base) {
System.out.println("Test: " + Arrays.toString(tap));
// Build the BigInteger.
BigInteger primitive = BigInteger.ZERO;
for (int bit : tap) {
primitive = primitive.or(BigInteger.ONE.shiftLeft(bit));
}
// Stop at 100.
int count = 100;
LFSR lfsr = new LFSR(primitive, BigInteger.ONE);
for (BigInteger b : lfsr) {
if (count-- > 0) {
System.out.println(b.toString(base));
} else {
break;
}
}
}
public void test() {
// Just 6 bits.
int[] tap7 = {6, 5, 0};
test(tap7, 10);
// An example 48-bit tap.
int[] tap48 = {48, 46, 45, 44, 42, 40, 36, 34, 33, 32, 29, 27, 26, 20, 17, 16, 12, 11, 10, 5, 3, 1, 0};
test(tap48, 32);
}
}
As you can see, the efficiency is very good - just a few boolean ops per iteration. You can therefore just iterate N times to get the number you want. Choose the number of bits to achieve at least the number of days you want.
Here are some steps to get you started:
1) Generate a random number
2) Check this random number against an array/hashmap/list/whatever.
3) If it doesn't exist, add it in
4) Find 'word of the day' using this number.
5) Repeat these steps
If the random number does exist, then simply generate another one. You would then repeat these steps everyday until the size of the 'already used numbers' array matches the length of the 'words of the day' array. However, this process is not very efficicent and I wouldn't necessarily use it, it is just here to get you thinking.
Some possibly better ideas:
If you never want it to be the same, instead of 'randomly generating' a number. Why not just iterate through an array to begin with and increase it every day?
You could also just generate a random number, find the word of the day and then delete it from your list of random words and repeat this process until the list is empty, ensuring you alter the boundaries of your random numbers each time. Then when it is empty, just repopulate it.
Create an array of these possible numbers and shuffle it.
Every day use the next index, starting at 0.
I am working on a problem from Cracking the Coding Interview, problem 9.6 page 110.
Here is the problem:
Implement an algorithm to print all valid (e.g., properly opened and closed combinations of n-pairs of parentheses. Examples
b(1) - "()"
b(2) - "(()), ()()"
b(3) - "((())), (()()), (())(), ()(()), ()()()"
I am trying to use the bottom up recursion approach that the author discusses on page 107 - "We start with knowing how to solve the problem for a simple case, like a list with only one element, and figure out how to solve the problem for two elements, then for three elements, and so on. The key here is to think about how you can build the solution for one case off the previous case"
Here is the code I have so far
static void print(int n) {
print(n, new HashSet<String>(), "", "");
}
static void print(int n, Set<String> combs, String start, String end) {
if(n == 0) {
if(!combs.contains(start + end)) {
System.out.print(start + end);
combs.add(start + end);
}
} else {
print(n-1, combs, "(" + start, end +")");
System.out.print(", ");
print(n-1, combs, start, end + "()");
System.out.print(", ");
print(n-1, combs, "()" + start, end);
}
}
To get this code, I worked from the first case to the second case. I saw that b(2) = "(b(1)), b(1),b(1)"
This code does work for the first two cases. I am really struggling with the third case though. Can someone give me a hint(not the whole answer, could turn to the back of the book for that), about how to go from case 2 to case 3, or in other words using case 2 to get to case 3? Like how would you go from (()), ()() to ((())), (()()), (())(), ()(()), ()()()? Would you abandon the pattern you saw from b(1) to b(2) because it doesn't work for b(2) to b(3)?
We can generate from b(n) to b(n + 1) by using this recursive formula:
(b(n - x))b(x) with 0 <= x <= n
So, you can have all of your combinations by iterating through all x.
Code:
public static ArrayList<String> cal(int num){
if(num == 0){
ArrayList<String> list = new ArrayList();
list.add("");
return list;
}else{
ArrayList<String>result = new ArrayList();
for(int i = 0; i <= num - 1; i++){
ArrayList<String> a = cal(i);
ArrayList<String> b = cal(num - 1 - i);
for(String x : a){
for(String y : b){
result.add("(" + x + ")" + y);
}
}
}
return result;
}
}
Input: 3
Output: ()()(), ()(()), (())(), (()()), ((()))
Input: 4
Output: ()()()(), ()()(()), ()(())(), ()(()()), ()((())), (())()(), (())(()), (()())(), ((()))(), (()()()), (()(())), ((())()), ((()())), (((())))
Thanks Khanna111 for pointing out the mistake I made in my original answer, which was incomplete and under-counted the string patterns. As a result, I have updated my answer accordingly.
Please consider giving credit to Pham Trung for his answer with the correct recursive formula. My answer is essentially the same as his, with only a slight difference in the way I formulate the construction of patterns from smaller sub-problems (as I find it easier to explain the details in my approach).
========================================================================
Update Solution
For any valid pattern s of size n, s falls in exactly one of the following cases:
Case 1: s cannot be partitioned into two valid patterns of smaller size
Case 2: s can be partitioned into two valid patterns of smaller size
For case 1, s must be of the form (_____), where _____ is a valid pattern of size n - 1. So in this case, for every valid pattern t of size n - 1, we simply construct a pattern s by concatenating t with ( and ) as prefix and suffix, respectively (i.e. s = (t)).
For case 2, we can partition s into uv, where u and v are both valid patterns of smaller size. In this case, we have to consider all possible patterns of u and v, where u can be any valid pattern of size i = 1, 2, ..., n - 1, while v can be any valid pattern of size n - i.
When n = 0, clearly only the empty string is a valid pattern, so we have dp(0) = { "" } as our base case. A complete implementation with caching to improve the performance is given below:
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
public class BalancingBrackets {
private static Map<Integer, Set<String>> dp = new HashMap<>();
public static void main(String[] args) {
Set<String> result = compute(4);
boolean isFirst = true;
for (String s : result) {
if (isFirst) {
isFirst = false;
System.out.print(s);
} else {
System.out.print(", " + s);
}
}
}
private static Set<String> compute(Integer n) {
// Return the cached result if available
if (dp.containsKey(n)) {
return dp.get(n);
}
Set<String> set = new HashSet<>();
if (n == 0) {
// This is the base case with n = 0, which consists only of the
// empty string
set.add("");
} else if (n > 0) {
// For generating patterns in case 1
for (String s : compute(n - 1)) {
set.add("(" + s + ")");
}
// For generating patterns in case 2
for (int i = 1; i < n; i++) {
Set<String> leftPatterns = compute(i);
Set<String> rightPatterns = compute(n - i);
for (String l : leftPatterns) {
for (String r : rightPatterns) {
set.add(l + r);
}
}
}
} else {
// Input cannot be negative
throw new IllegalArgumentException("Input cannot be negative.");
}
// Cache the solution to save time for computing large size problems
dp.put(n, set);
return set;
}
}
I am working on an algorithm, and I need to be able to pass in a List and see if there are four numbers in a row at any point in the list.
I have been struggling with an easy way to do this... Here is the basic idea.. I would like the fourNumbersInARow() method to return true:
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
public class Numbers {
/**
* #param args
*/
public static void main(String[] args) {
List<Integer> numbers = new ArrayList<Integer>();
for(int i = 0; i<10; i++){
numbers.add((new Random().nextInt()));
}
numbers.add(1);
numbers.add(2);
numbers.add(3);
numbers.add(4);
System.out.println(fourNumbersInARow());
}
private static boolean fourNumbersInARow() {
}
}
Use two variables: last_value and row_count. Going through the list one by one, always look whether the current value is exactly one bigger than the last_value; if yes, increase row_count, if no, reset it to 1. In any case, set last_value to the current value and loop. If at any point row_count becomes 4, return true. If you reach the end of the list, return false.
EDIT: changed counter range to start at 1
Here's an implementation in Java.
static boolean fourNumbersInARow(List<Integer> list) {
int last = 0xFACADE; // can be any number
int count = 0; // important!
for (int i : list) {
if (i == last + 1) {
if (++count == 4) return true;
} else {
count = 1;
}
last = i;
}
return false;
}
Unlike others, this resets the count of numbers in a row to 1 when the sequence is broken (because a number on its own is 1 number in a row). This allows for easier treatment of the first iteration where technically there is no previous number.
In pseudocode:
consecutiveCount = 1
lastNumber = firstElementInList(list)
for (number in list.fromSecondElement()):
if (number - lastNumber == 1):
consecutiveCount++
else:
consecutiveCount = 1
if (consecutiveCount == 4):
return true
lastNumber = number
return false
The bottom line is, you'll want to keep track of the last number in that was in the list, and compare it with the current number to see if the difference is 1. In order to remember the last number, a variable such as lastNumber is needed.
Then, in order to keep track of how many consecutive numbers there have been there should be a counter for that as well, which in the example about is the consecutiveCount.
When the condition where four consecutive numbers have occurred, then the method should return true.
This sounds a little like a homework question, so I don't want to write out a complete solution. But in your method just iterate through the list. Take the first number and see if the next number comes after the current, if so then set a variable flag with the start position and the current number, on the next iteration through the loop check to see if that value is before the previous the value etc... Once four in a row are found, break out of the loop and return true. If you encounter a number that is no chronologically correct then set a flag(start location) to null or negative and start the process over from the current location in the list.
Check this Code, this will return true if there a sequence of 4 numbers and else false otherwise
public class FindFourSequence {
public boolean isFourinRow(ArrayList seqList) {
boolean flag = false;
int tempValue = 0;
int tempValue2 = 0;
int tempValue3 = 0;
int tempValue4 = 0;
Iterator iter = seqList.iterator();
while(iter.hasNext()){
String s1 = (String)iter.next();
tempValue=Integer.valueOf(s1).intValue();
if(!(iter.hasNext())){
break;
}
String s2 = (String)iter.next();
tempValue2=Integer.valueOf(s2).intValue();
if(((tempValue2-tempValue)==1) || (tempValue-tempValue2)==1){
if(!(iter.hasNext())){
break;
}
String s3 = (String)iter.next();
tempValue3=Integer.valueOf(s3).intValue();
if((tempValue3-tempValue2)==1 || (tempValue2-tempValue3)==1){
if(!(iter.hasNext())){
break;
}
String s4 = (String)iter.next();
tempValue4=Integer.valueOf(s4).intValue();
if((tempValue3-tempValue4==1) || (tempValue4-tempValue3)==1){
flag = true;
return flag;
}
}
}
}
return flag;
}
public static void main(String[] args) throws Exception {
ArrayList aList = new ArrayList();
boolean flag = false;
FindFourSequence example = new FindFourSequence();
Random random = new Random();
for (int k = 0; k < 25; k++) {
int number = random.nextInt(20);
System.out.println(" the Number is :" + number);
aList.add("" + number);
}
/* aList.add("" + 1);
aList.add("" + 2);
aList.add("" + 3);
aList.add("" + 4);*/
flag = example.isFourinRow(aList);
System.out.println(" the result value is : " + flag);
}
}