diff --git a/src/main/java/Parentheses.java b/src/main/java/Parentheses.java new file mode 100644 index 0000000..c833c3b --- /dev/null +++ b/src/main/java/Parentheses.java @@ -0,0 +1,85 @@ +import java.util.Arrays; +import java.util.HashSet; +import java.util.LinkedList; +import java.util.List; +import java.util.Set; + +/** + * Created by sam on 3/7/17. + */ +public class Parentheses { + + public static List generateParentheses(int n) { + + if(n == 0) { + return new LinkedList(Arrays.asList("")); + } + if(n == 1) { + return new LinkedList(Arrays.asList("()")); + } + // brute force is to start with a string of n good parentheses '()' + // then starting from right, grab first open parentheses, move to the left until at start + // each iteration check for valid set of parentheses, and add to results list + // then do n-- and find next open parentheses, to find all n open parentheses + // actually use a hash set to only keep a set of combos + Set results = new HashSet<>(); + StringBuilder str = new StringBuilder(); + for(int i = 1; i <= n; i++){ + str.append("()"); + } + results.add(str.toString()); + + for(int i = 2; i <= n; i++) { +// int l = str.lastIndexOf("("); + int l = str.indexOf("("); + // grab i-th from front '(' + for(int k = 2; k <= i; k++) { + l = str.indexOf("(", l + 1); + } + // pull that '(' to front + for(int j = l - 1; j >= 0; j--) { + str.setCharAt(j + 1, str.charAt(j)); + str.setCharAt(j, '('); + if(isValidParenthesesString(str.toString()) && ! results.contains(str.toString())) { + results.add(str.toString()); + } + } + } + + for(int i = 1; i < n; i++) { +// int l = str.lastIndexOf("("); + int l = str.indexOf(")"); + // grab i-th from front '(' + for(int k = 2; k <= i; k++) { + l = str.indexOf(")", l + 1); + } + // + for(int j = l - 1; j > 0; j--) { + // in this boolean, replace '(' then length() will count ')' + if (str.substring(j + 2).replace("(", "").length() > str.substring(j + 2).replace(")", "").length()) { + str.setCharAt(j + 1, str.charAt(j)); + str.setCharAt(j, ')'); + if(! results.contains(str.toString()) && isValidParenthesesString(str.toString()) ) { + results.add(str.toString()); + } + } + } + } + return new LinkedList<>(results); + + } + + private static boolean isValidParenthesesString(String s) { + int left = 0; + int right = 0; + for(int i = 0; i < s.length(); i++) { + if(s.charAt(i) == '(') left++; + if(s.charAt(i) == ')') right++; + if(right > left) return false; + } + // if (, left++; if ), right++ + // if right > left, return false + return true; + } + +} diff --git a/src/main/java/PartitioningPalindromes.java b/src/main/java/PartitioningPalindromes.java new file mode 100644 index 0000000..224ba87 --- /dev/null +++ b/src/main/java/PartitioningPalindromes.java @@ -0,0 +1,152 @@ +import java.util.LinkedList; +import java.util.List; + +class PartitioningPalindromes { + /** + * Given a string, print all palindromic partitions. + */ + public static List> partition(String input) throws IllegalArgumentException { + if(input.isEmpty() || input == null){ + throw new IllegalArgumentException("invalid inputs to partition(), requires string of length >= 1"); + } + + // solution is a single possible palindromic partition + // palindromic partition is a way to split chars of input string that still contains all palindromes + List solution = new LinkedList<>(); + + // palindromes is all the possible solutions for str of length = n + List> output = new LinkedList<>(); + if(input.length() == 1) { + solution.add(input); + output.add(solution); + return output; + } + + // we create a List of outputs for each substring of length 1 -> n + List>> outputList = new LinkedList<>(); + + // string.substring is 0 indexed, exclusive top end + solution.add(input.substring(0,1)); + output.add(solution); + outputList.add(output); + // cursor is 0 indexed, like input string, and starts at second char bc input.length > 1 + int cursor = 1; + while(cursor < input.length()) { + String newChar = input.substring(cursor, cursor + 1); + // first add new char to all solutions from previous output + // 1. copy output to newOutput + // 2. for each solution in output:append new char to solution, add new solution to newOutput + List> newOutput = new LinkedList<>(); + for (List subSolution : output) { + solution = new LinkedList<>(subSolution); + solution.add(newChar); + newOutput.add(solution); + } + // then check all possible substrings from right to left for palindromes + for(int pivot = cursor - 1; pivot >= 0; pivot--) { + String mirror = input.substring(pivot, pivot + 1); + if(mirror.equals(newChar) && isPalindrome(input.substring(pivot + 1, cursor))) { + String palindrome = input.substring(pivot, cursor + 1); + if(pivot == 0) { + solution = new LinkedList<>(); + solution.add(palindrome); + newOutput.add(solution); + } else { + output = outputList.get(pivot - 1); + for (List subSolution : output) { + solution = new LinkedList<>(subSolution); + solution.add(palindrome); + newOutput.add(solution); + } + } + } + } + outputList.add(newOutput); + output = newOutput; + cursor++; + } + // return output for string length = n, which is all palindromes for input string + return output; + } + + public static List> partitionBinaryMethod(String input) throws IllegalArgumentException { + List> output = new LinkedList<>(); + // binary method makes a binary number with n - 1 bits, to act as boolean flags + // if the flag is 1 then there is a slice in the string at that space between characters + // iterate from max value of binary number of bits n - 1, i--, i > 0, and check possible solution + + int i = (int) Math.pow(2, input.length() - 1) - 1; + while(i >= 0) { + String bits = Integer.toBinaryString(i); + // bits is string representation of i in binary + // as we decrement, we will need to 0 pad the left of bits + if(bits.length() < input.length() - 1) { + // should use string builder + String pad = ""; + int padLength = input.length() - 1 - bits.length(); + for(int j = padLength; j > 0; j--) { + pad += "0"; + } + bits = pad + bits; + } + + // solution is a unique way to split input string into palindromic partitions + List solution = new LinkedList<>(); + // take binary string of splits and apply to input + // ints c and s, cursor and scissors, cursor is last slice, scissors increments + // when scissors finds a 1 in bit string, cuts substring from cursor to scissors + // then cursor gets moved up to scissors, add substring to solution + for(int s = 0, c = 0; s < bits.length(); s++) { + if(bits.charAt(s) == '1') { + String slice = input.substring(c, s + 1); + c = s + 1; + solution.add(slice); + } + if (bits.length() == s + 1) { + // s is at last char and last char is 0, just grab end of input from cursor + String slice = input.substring(c); + solution.add(slice); + } + } + + // if solution is palindromic, add to output List> + if(isPalindrome(solution)) { + output.add(solution); + } + i--; + } + + return output; + } + private static boolean isPalindrome(List input) { + for (String partition : input) { + if(! isPalindrome(partition)) { + return false; + } + } + return true; + } + private static boolean isPalindrome(String input) { + if(input.isEmpty()) { + return true; + } + char[] str = input.toCharArray(); + int left, right; + if(str.length % 2 == 1) { + left = ((str.length - 1) / 2) - 1; + right = left + 2; + } else { + left = (str.length / 2) - 1; + right = left + 1; + } + while(left >= 0 && right < str.length) { + if(str[left] != str[right]) { + return false; + } else { + left--; + right++; + } + } + return true; + } +} diff --git a/src/test/java/ParenthesesTest.java b/src/test/java/ParenthesesTest.java new file mode 100644 index 0000000..bcb06e1 --- /dev/null +++ b/src/test/java/ParenthesesTest.java @@ -0,0 +1,51 @@ +import org.junit.Assert; +import org.junit.Test; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +/** + * Created by sam on 6/17/16. + */ +public class ParenthesesTest { + + + @Test + public void test1() { + List expected = Arrays.asList( + "()"); + Assert.assertEquals(expected.size(), Parentheses.generateParentheses(1).size()); + } + + + @Test + public void test2() { + List expected = Arrays.asList( + "(())", + "()()"); + Assert.assertEquals(expected.size(), Parentheses.generateParentheses(2).size()); + } + + @Test + public void test3() { + List expected = Arrays.asList( + "((()))", + "(()())", + "(())()", + "()(())", + "()()()"); +// Assert.assertEquals(expected, Parentheses.generateParentheses(3)); + Assert.assertEquals(expected.size(), Parentheses.generateParentheses(3).size()); + } + + + @Test + public void test4() { + List expected = Arrays.asList("()()()()", "(())()()", "(((())))", "()((()))", "(()())()", "(()(()))", "()()(())", "()(()())", "((()()))", "((()))()", "((())())"); +// Assert.assertEquals(expected, Parentheses.generateParentheses(4)); + Assert.assertEquals(expected.size(), Parentheses.generateParentheses(4).size()); + } + + +} diff --git a/src/test/java/PartitioningPalindromesTest.java b/src/test/java/PartitioningPalindromesTest.java new file mode 100644 index 0000000..3be0bd6 --- /dev/null +++ b/src/test/java/PartitioningPalindromesTest.java @@ -0,0 +1,218 @@ +import org.junit.Assert; +import org.junit.Test; + +import java.util.Arrays; +import java.util.List; + +public class PartitioningPalindromesTest { + + public void compareExpectedWithActual(List> expected, List> actual) { + Assert.assertTrue("Size between expected and actual needs to match", expected.size() == actual.size()); + for (List expectedPartitioning : expected) { + String errorMessage = "Failed to find: '" + expectedPartitioning + "' in actuals"; + Assert.assertTrue(errorMessage, actual.contains(expectedPartitioning)); + } + } + + @Test + public void testCase1() { + String input = "fff"; + List> expected = Arrays.asList( + Arrays.asList("f", "f", "f"), + Arrays.asList("f", "ff"), + Arrays.asList("ff", "f"), + Arrays.asList("fff") + ); + List> actual = PartitioningPalindromes.partition(input); + compareExpectedWithActual(expected, actual); + } + + @Test + public void testCaseBinaryMethod1() { + String input = "fff"; + List> expected = Arrays.asList( + Arrays.asList("f", "f", "f"), + Arrays.asList("f", "ff"), + Arrays.asList("ff", "f"), + Arrays.asList("fff") + ); + List> actual = PartitioningPalindromes.partitionBinaryMethod(input); + compareExpectedWithActual(expected, actual); + } + + @Test + public void testCase2() { + String input = "racecar"; + List> expected = Arrays.asList( + Arrays.asList("r", "a", "c", "e", "c", "a", "r"), + Arrays.asList("r", "a", "cec", "a", "r"), + Arrays.asList("r", "aceca", "r"), + Arrays.asList("racecar") + ); + List> actual = PartitioningPalindromes.partition(input); + compareExpectedWithActual(expected, actual); + } + + @Test + public void testCaseBinaryMethod2() { + String input = "racecar"; + List> expected = Arrays.asList( + Arrays.asList("r", "a", "c", "e", "c", "a", "r"), + Arrays.asList("r", "a", "cec", "a", "r"), + Arrays.asList("r", "aceca", "r"), + Arrays.asList("racecar") + ); + List> actual = PartitioningPalindromes.partitionBinaryMethod(input); + compareExpectedWithActual(expected, actual); + } + + @Test + public void testCase3() { + String input = "bbcccdddd"; + // this problem is an example of combinatorial explosion + List> expected = Arrays.asList( + Arrays.asList("b", "b", "c", "c", "c", "d", "d", "d", "d"), + Arrays.asList("bb", "c", "c", "c", "d", "d", "d", "d"), + Arrays.asList("b", "b", "cc", "c", "d", "d", "d", "d"), + Arrays.asList("bb", "cc", "c", "d", "d", "d", "d"), + Arrays.asList("b", "b", "c", "cc", "d", "d", "d", "d"), + Arrays.asList("bb", "c", "cc", "d", "d", "d", "d"), + Arrays.asList("b", "b", "ccc", "d", "d", "d", "d"), + Arrays.asList("bb", "ccc", "d", "d", "d", "d"), + Arrays.asList("b", "b", "c", "c", "c", "dd", "d", "d"), + Arrays.asList("bb", "c", "c", "c", "dd", "d", "d"), + Arrays.asList("b", "b", "cc", "c", "dd", "d", "d"), + Arrays.asList("bb", "cc", "c", "dd", "d", "d"), + Arrays.asList("b", "b", "c", "cc", "dd", "d", "d"), + Arrays.asList("bb", "c", "cc", "dd", "d", "d"), + Arrays.asList("b", "b", "ccc", "dd", "d", "d"), + Arrays.asList("bb", "ccc", "dd", "d", "d"), + Arrays.asList("b", "b", "c", "c", "c", "d", "dd", "d"), + Arrays.asList("bb", "c", "c", "c", "d", "dd", "d"), + Arrays.asList("b", "b", "cc", "c", "d", "dd", "d"), + Arrays.asList("bb", "cc", "c", "d", "dd", "d"), + Arrays.asList("b", "b", "c", "cc", "d", "dd", "d"), + Arrays.asList("bb", "c", "cc", "d", "dd", "d"), + Arrays.asList("b", "b", "ccc", "d", "dd", "d"), + Arrays.asList("bb", "ccc", "d", "dd", "d"), + Arrays.asList("b", "b", "c", "c", "c", "ddd", "d"), + Arrays.asList("bb", "c", "c", "c", "ddd", "d"), + Arrays.asList("b", "b", "cc", "c", "ddd", "d"), + Arrays.asList("bb", "cc", "c", "ddd", "d"), + Arrays.asList("b", "b", "c", "cc", "ddd", "d"), + Arrays.asList("bb", "c", "cc", "ddd", "d"), + Arrays.asList("b", "b", "ccc", "ddd", "d"), + Arrays.asList("bb", "ccc", "ddd", "d"), + Arrays.asList("b", "b", "c", "c", "c", "d", "d", "dd"), + Arrays.asList("bb", "c", "c", "c", "d", "d", "dd"), + Arrays.asList("b", "b", "cc", "c", "d", "d", "dd"), + Arrays.asList("bb", "cc", "c", "d", "d", "dd"), + Arrays.asList("b", "b", "c", "cc", "d", "d", "dd"), + Arrays.asList("bb", "c", "cc", "d", "d", "dd"), + Arrays.asList("b", "b", "ccc", "d", "d", "dd"), + Arrays.asList("bb", "ccc", "d", "d", "dd"), + Arrays.asList("b", "b", "c", "c", "c", "dd", "dd"), + Arrays.asList("bb", "c", "c", "c", "dd", "dd"), + Arrays.asList("b", "b", "cc", "c", "dd", "dd"), + Arrays.asList("bb", "cc", "c", "dd", "dd"), + Arrays.asList("b", "b", "c", "cc", "dd", "dd"), + Arrays.asList("bb", "c", "cc", "dd", "dd"), + Arrays.asList("b", "b", "ccc", "dd", "dd"), + Arrays.asList("bb", "ccc", "dd", "dd"), + Arrays.asList("b", "b", "c", "c", "c", "d", "ddd"), + Arrays.asList("bb", "c", "c", "c", "d", "ddd"), + Arrays.asList("b", "b", "cc", "c", "d", "ddd"), + Arrays.asList("bb", "cc", "c", "d", "ddd"), + Arrays.asList("b", "b", "c", "cc", "d", "ddd"), + Arrays.asList("bb", "c", "cc", "d", "ddd"), + Arrays.asList("b", "b", "ccc", "d", "ddd"), + Arrays.asList("bb", "ccc", "d", "ddd"), + Arrays.asList("b", "b", "c", "c", "c", "dddd"), + Arrays.asList("bb", "c", "c", "c", "dddd"), + Arrays.asList("b", "b", "cc", "c", "dddd"), + Arrays.asList("bb", "cc", "c", "dddd"), + Arrays.asList("b", "b", "ccc", "dddd"), + Arrays.asList("bb", "ccc", "dddd"), + Arrays.asList("b", "b", "c", "cc", "dddd"), + Arrays.asList("bb", "c", "cc", "dddd") + ); + List> actual = PartitioningPalindromes.partition(input); + compareExpectedWithActual(expected, actual); + } + + + @Test + public void testCaseBinaryMethod3() { + String input = "bbcccdddd"; + // this problem is an example of combinatorial explosion + List> expected = Arrays.asList( + Arrays.asList("b", "b", "c", "c", "c", "d", "d", "d", "d"), + Arrays.asList("bb", "c", "c", "c", "d", "d", "d", "d"), + Arrays.asList("b", "b", "cc", "c", "d", "d", "d", "d"), + Arrays.asList("bb", "cc", "c", "d", "d", "d", "d"), + Arrays.asList("b", "b", "c", "cc", "d", "d", "d", "d"), + Arrays.asList("bb", "c", "cc", "d", "d", "d", "d"), + Arrays.asList("b", "b", "ccc", "d", "d", "d", "d"), + Arrays.asList("bb", "ccc", "d", "d", "d", "d"), + Arrays.asList("b", "b", "c", "c", "c", "dd", "d", "d"), + Arrays.asList("bb", "c", "c", "c", "dd", "d", "d"), + Arrays.asList("b", "b", "cc", "c", "dd", "d", "d"), + Arrays.asList("bb", "cc", "c", "dd", "d", "d"), + Arrays.asList("b", "b", "c", "cc", "dd", "d", "d"), + Arrays.asList("bb", "c", "cc", "dd", "d", "d"), + Arrays.asList("b", "b", "ccc", "dd", "d", "d"), + Arrays.asList("bb", "ccc", "dd", "d", "d"), + Arrays.asList("b", "b", "c", "c", "c", "d", "dd", "d"), + Arrays.asList("bb", "c", "c", "c", "d", "dd", "d"), + Arrays.asList("b", "b", "cc", "c", "d", "dd", "d"), + Arrays.asList("bb", "cc", "c", "d", "dd", "d"), + Arrays.asList("b", "b", "c", "cc", "d", "dd", "d"), + Arrays.asList("bb", "c", "cc", "d", "dd", "d"), + Arrays.asList("b", "b", "ccc", "d", "dd", "d"), + Arrays.asList("bb", "ccc", "d", "dd", "d"), + Arrays.asList("b", "b", "c", "c", "c", "ddd", "d"), + Arrays.asList("bb", "c", "c", "c", "ddd", "d"), + Arrays.asList("b", "b", "cc", "c", "ddd", "d"), + Arrays.asList("bb", "cc", "c", "ddd", "d"), + Arrays.asList("b", "b", "c", "cc", "ddd", "d"), + Arrays.asList("bb", "c", "cc", "ddd", "d"), + Arrays.asList("b", "b", "ccc", "ddd", "d"), + Arrays.asList("bb", "ccc", "ddd", "d"), + Arrays.asList("b", "b", "c", "c", "c", "d", "d", "dd"), + Arrays.asList("bb", "c", "c", "c", "d", "d", "dd"), + Arrays.asList("b", "b", "cc", "c", "d", "d", "dd"), + Arrays.asList("bb", "cc", "c", "d", "d", "dd"), + Arrays.asList("b", "b", "c", "cc", "d", "d", "dd"), + Arrays.asList("bb", "c", "cc", "d", "d", "dd"), + Arrays.asList("b", "b", "ccc", "d", "d", "dd"), + Arrays.asList("bb", "ccc", "d", "d", "dd"), + Arrays.asList("b", "b", "c", "c", "c", "dd", "dd"), + Arrays.asList("bb", "c", "c", "c", "dd", "dd"), + Arrays.asList("b", "b", "cc", "c", "dd", "dd"), + Arrays.asList("bb", "cc", "c", "dd", "dd"), + Arrays.asList("b", "b", "c", "cc", "dd", "dd"), + Arrays.asList("bb", "c", "cc", "dd", "dd"), + Arrays.asList("b", "b", "ccc", "dd", "dd"), + Arrays.asList("bb", "ccc", "dd", "dd"), + Arrays.asList("b", "b", "c", "c", "c", "d", "ddd"), + Arrays.asList("bb", "c", "c", "c", "d", "ddd"), + Arrays.asList("b", "b", "cc", "c", "d", "ddd"), + Arrays.asList("bb", "cc", "c", "d", "ddd"), + Arrays.asList("b", "b", "c", "cc", "d", "ddd"), + Arrays.asList("bb", "c", "cc", "d", "ddd"), + Arrays.asList("b", "b", "ccc", "d", "ddd"), + Arrays.asList("bb", "ccc", "d", "ddd"), + Arrays.asList("b", "b", "c", "c", "c", "dddd"), + Arrays.asList("bb", "c", "c", "c", "dddd"), + Arrays.asList("b", "b", "cc", "c", "dddd"), + Arrays.asList("bb", "cc", "c", "dddd"), + Arrays.asList("b", "b", "ccc", "dddd"), + Arrays.asList("bb", "ccc", "dddd"), + Arrays.asList("b", "b", "c", "cc", "dddd"), + Arrays.asList("bb", "c", "cc", "dddd") + ); + List> actual = PartitioningPalindromes.partitionBinaryMethod(input); + compareExpectedWithActual(expected, actual); + } + +} diff --git a/src/test/java/XMLParserTest.java b/src/test/java/XMLParserTest.java new file mode 100644 index 0000000..5416e1b --- /dev/null +++ b/src/test/java/XMLParserTest.java @@ -0,0 +1,26 @@ +/** + * Created by sam on 1/9/17. + */ +public class XMLParserTest { + + // this will test a few xml files + // take an xml file, parse to json, output to file + // take an optional second parameter which is a json file that explains the hierarchy of the xml + // a few tests with second parameter, a few without (how does it work without understanding the hierarchy + + + // the algo has an underlying parser that does two things: + /* + 1. reads a text file, understands new lines(maybe strips them out) and trims the file to the first tag + 2. with each tag, denoted by <.*>, finds closing tag , or finds closing tag of a different tag + a. with its own closing tag, creates object with tag as prop name, and + i. string contents as value // contents + ii. or restarts parser at new tag // stuff + b. with closing tag of different tag // ......... + i. goes from tag to tag2, makes objects and restarts parser to recurse each closing/then/opening tag including open tag2 + + then the algo outputs that to json, formatted nicely? what is true json? + + */ + +}