I have implemented the question #268 from Topcoder. The question is that there are 4 conditions for a lottery ticket:
- CHOICES - numbers available (10 ≤ CHOICES ≤ 100)
- BLANKS - number of numbers that can be chosen (1 ≤ BLANKS ≤ 8)
- SORTED - are the numbers sorted
- UNIQUE - are the numbers unique
The input is given as
(CHOICES, BLANKS, SORTED, UNIQUE)
For example, when the conditions are
CHOICES = 15, BLANKS = 4, SORTED = FALSE and UNIQUE = TRUE
one of the values possible is
{3, 7, 12, 14}
Suppose these are the inputs: (in the format NAME: CHOICES BLANKS SORTED UNIQUE)
{"PICK ANY TWO: 10 2 F F",
"PICK TWO IN ORDER: 10 2 T F",
"PICK TWO DIFFERENT: 10 2 F T",
"PICK TWO LIMITED: 10 2 T T"}
The number of ways in which these can happen is:
PICK ANY TWO - 100 i.e (10 * 10)
PICK TWO IN ORDER - 55
PICK TWO DIFFERENT - 90 i.e. (10 * 9) i.e. 10!/(10-2)!
PICK TWO LIMITED - 45 i.e. 10!/2!(10-2)!
And the output is:
PICK TWO LIMITED
PICK TWO IN ORDER
PICK TWO DIFFERENT
PICK ANY TWO
I would like to have some suggestions for:
- Code structure
- Test cases that could be added
- Errors that can be found
Main Class
Lottery
public class Lottery {
public String[] sortByOdds(String[] rules) {
Rule[] rule = new Rule[rules.length];
for (int i = 0; i < rules.length; i++) {
rule[i] = parseStringAndCreateRule(rules[i]);
}
MergeSort.sort(rule);
// MergeSort is REQUIRED because we shouldn't change the order of Rules
// if 2 (or more) Rules have the same Odds. This is not guaranteed with
// Array.sort().
// Arrays.sort(rule);
String[] namesOfRules = new String[rule.length];
for (int i = 0; i < rule.length; i++) {
namesOfRules[i] = rule[i].name;
}
return namesOfRules;
}
private Rule parseStringAndCreateRule(String rule) {
StringTokenizer strTokenizer = new StringTokenizer(rule, ":");
String name = strTokenizer.nextToken().trim();
String[] conditions = strTokenizer.nextToken().trim().split(" ");
return new Rule(name, conditions);
}
}
Other Helper Classes
Rule
public class Rule implements Comparable<Rule> {
String name;
String[] conditions;
int noOfChoices;
int noOfBlanks;
boolean isSorted;
boolean isUnique;
BigInteger numberOfOdds;
public Rule(String name, String[] conditions) {
this.name = name;
this.conditions = conditions;
checkAndAssignConditions(conditions);
calculateOdds();
}
private void checkAndAssignConditions(String[] conditions) {
try {
if (conditions.length != 4) {
throw new IllegalArgumentException(
"Number of conditions should be 4");
}
noOfChoices = Integer.valueOf(conditions[0]);
noOfBlanks = Integer.valueOf(conditions[1]);
if (conditions[2].length() != 1 || conditions[3].length() != 1) {
throw new InvalidAttributesException(
"Conditions Sorted and Unique should be of length 1");
}
if (String.valueOf(conditions[2]).equalsIgnoreCase("T")) {
isSorted = true;
} else if (String.valueOf(conditions[2]).equalsIgnoreCase("F")) {
isSorted = false;
} else {
throw new InvalidAttributesException(
"Sorted should either be TRUE of FALSE");
}
if (String.valueOf(conditions[3]).equalsIgnoreCase("T")) {
isUnique = true;
} else if (String.valueOf(conditions[3]).equalsIgnoreCase("F")) {
isUnique = false;
} else {
throw new InvalidAttributesException(
"Unique should either be TRUE of FALSE");
}
} catch (NumberFormatException e) {
System.out.println(e.getMessage());
e.printStackTrace();
} catch (InvalidAttributesException e) {
System.out.println(e.getMessage());
e.printStackTrace();
} catch (RuntimeException e) {
System.out.println(e.getMessage());
e.printStackTrace();
}
}
private void calculateOdds() {
if (!isSorted && !isUnique) {
numberOfOdds = LotteryUtils.getNoOfDrawsForNotSortedNotUnique(
noOfChoices, noOfBlanks);
} else if (isSorted && !isUnique) {
numberOfOdds = LotteryUtils.getNoOfDrawsForSortedNotUnique(
noOfChoices, noOfBlanks);
} else if (!isSorted && isUnique) {
numberOfOdds = LotteryUtils.getNoOfDrawsForNotSortedUnique(
noOfChoices, noOfBlanks);
} else if (isSorted && isUnique) {
numberOfOdds = LotteryUtils.getNoOfDrawsForSortedUnique(
noOfChoices, noOfBlanks);
}
}
@Override
public int compareTo(Rule o) {
return numberOfOdds.compareTo(o.numberOfOdds);
}
}
LotteryUtils
public class LotteryUtils {
private static BigInteger getPow(int n, int r) {
BigInteger noOfDraws = new BigInteger("1");
for (int i = 0; i < r; i++) {
noOfDraws = noOfDraws.multiply(BigInteger.valueOf(n));
}
return noOfDraws;
}
private static BigInteger getFactorial(int n) {
BigInteger factorial = new BigInteger("1");
for (int i = 1; i <= n; i++) {
factorial = factorial.multiply(BigInteger.valueOf(i));
}
return factorial;
}
public static BigInteger getCombination(int n, int r) {
BigInteger rFactorial = new BigInteger("1");
BigInteger numeratorPart = new BigInteger("1");
if (n == r)
return new BigInteger("1");
for (int i = 0; i < r; i++) {
numeratorPart = numeratorPart.multiply(BigInteger.valueOf(n - i));
}
rFactorial = getFactorial(r);
return numeratorPart.divide(rFactorial);
}
public static BigInteger getPermutation(int n, int r) {
if (n == r)
return getFactorial(n);
else
return getFactorial(n).divide(getFactorial(n - r));
}
public static BigInteger getNoOfDrawsForNotSortedNotUnique(int n, int r) {
return getPow(n, r);
}
public static BigInteger getNoOfDrawsForSortedNotUnique(int n, int r) {
// SEE: Stars and Bars (Combinatorics)
return getCombination(n + r - 1, r);
}
public static BigInteger getNoOfDrawsForNotSortedUnique(int n, int r) {
return getPermutation(n, r);
}
public static BigInteger getNoOfDrawsForSortedUnique(int n, int r) {
return getCombination(n, r);
}
}
TestCase
LotteryTest
public class LotteryTest {
@Test
public void testGetCombination() {
assertEquals(new BigInteger("45"), LotteryUtils.getCombination(10, 2));
assertEquals(new BigInteger("1"), LotteryUtils.getCombination(10, 10));
assertEquals(new BigInteger("1"), LotteryUtils.getCombination(10, 0));
assertEquals(new BigInteger("210"), LotteryUtils.getCombination(10, 4));
assertEquals(new BigInteger("210"), LotteryUtils.getCombination(10, 6));
assertEquals(new BigInteger("252"), LotteryUtils.getCombination(10, 5));
assertEquals(LotteryUtils.getCombination(11, 6),
LotteryUtils.getCombination(11, 5));
}
@Test
public void testGetPermutation() {
assertEquals(new BigInteger("90"), LotteryUtils.getPermutation(10, 2));
}
@Test
public void testSortByOdds() {
Lottery lottery = new Lottery();
String[] lotteryTest;
String[] lotterySolution = { "PICK TWO LIMITED", "PICK TWO IN ORDER",
"PICK TWO DIFFERENT", "PICK ANY TWO" };
String[] lotterySolution2 = { "RED", "ORANGE", "YELLOW", "GREEN",
"BLUE", "INDIGO", "VIOLET" };
String[] lotterySolution3 = {};
lotteryTest = lottery.sortByOdds(new String[] {
"PICK ANY TWO: 10 2 F F", "PICK TWO IN ORDER: 10 2 T F",
"PICK TWO DIFFERENT: 10 2 F T", "PICK TWO LIMITED: 10 2 T T" });
assertEquals(lotteryTest.length, lotterySolution.length);
for (int i = 0; i < lotteryTest.length; i++) {
assertEquals(lotteryTest[i], lotterySolution[i]);
}
lotteryTest = lottery.sortByOdds(new String[] { "INDIGO: 93 8 T F",
"ORANGE: 29 8 F T", "VIOLET: 76 6 F F", "BLUE: 100 8 T T",
"RED: 99 8 T T", "GREEN: 78 6 F T", "YELLOW: 75 6 F F" });
assertEquals(lotteryTest.length, lotterySolution2.length);
for (int i = 0; i < lotteryTest.length; i++) {
assertEquals(lotteryTest[i], lotterySolution2[i]);
}
lotteryTest = lottery.sortByOdds(new String[] {});
assertEquals(lotteryTest.length, lotterySolution3.length);
for (int i = 0; i < lotteryTest.length; i++) {
assertEquals(lotteryTest[i], lotterySolution3[i]);
}
}
}
Sort Implementation
Merge Sort
public class MergeSort {
@SuppressWarnings("rawtypes")
private static void merge(Comparable[] a, Comparable[] aux, int lo,
int mid, int hi) {
for (int i = lo; i <= hi; i++) {
aux[i] = a[i];
}
int i = lo, j = mid + 1;
for (int k = lo; k <= hi; k++) {
if (j > hi)
a[k] = aux[i++];
else if (i > mid)
a[k] = aux[j++];
else if (less(aux[i], aux[j]))
a[k] = aux[i++];
else
a[k] = aux[j++];
}
}
@SuppressWarnings({ "rawtypes", "unchecked" })
private static boolean less(Comparable v, Comparable w) {
return (v.compareTo(w) < 0);
}
@SuppressWarnings("rawtypes")
private static void sort(Comparable[] a, Comparable[] aux, int lo, int hi) {
if (hi <= lo)
return;
int mid = lo + (hi - lo) / 2;
sort(a, aux, lo, mid);
sort(a, aux, mid + 1, hi);
// Merge the two sorted subarrays
merge(a, aux, lo, mid, hi);
}
@SuppressWarnings("rawtypes")
public static void sort(Comparable[] a) {
Comparable[] aux = new Comparable[a.length];
sort(a, aux, 0, a.length - 1);
}
}
The entire repository is hosted at GitHub.
1) testSortByOdds(LotteryTest) org.junit.ComparisonFailure: expected:<[INDIGO]> but was:<[BLUE]>
– 200_success♦ Jan 24 at 11:45import
statements as well. – 200_success♦ Jan 24 at 12:21MergeSort
implementation as well, it will not cause any errors any more. – yadav_vi Jan 25 at 13:07