/**
* Nathaniel Lim
* Williams College, CS136 Spring 2008
* LAB 2: Recursion
* February 25, 2008
* njl2@williams.edu
*/
import java.util.ArrayList;
public class Recursion {
private static final String delimiter = ", ";
public static void main (String [] args) {
}
/**
* static test methods of each recursive method.
*/
public static void testSumDigits(){
System.out.println(sumDigits(1234));
}
public static void testCountcannonballs(){
System.out.println(countCannonballs(4));
}
public static void testIsPalindrome(){
System.out.println("hannah " + isPalindrome("hannah") );
System.out.println("computer " + isPalindrome("computer") );
}
public static void testIsBalanced(){
System.out.println("[{}()] " + isBalanced("[{}()]"));
System.out.println("{{}{}())(]] " + isBalanced("{{}{}())(]]"));
}
public static void testSubstring(){
ArrayList<String> result = new ArrayList<String>();
generateSubstrings("ABCD", result);
printArray(result);
}
public static void testPerm(){
ArrayList<String> result = new ArrayList<String>();
generatePermutations("ABCD", result);
printArray(result);
}
public static void testToBinary(){
for (int i = 0; i < 33; i++) {
System.out.println("i" + ": " + toBinary(i) );
}
}
public static void testSubsetSum(){
int [] set = {1, 2, 3, 4, 5};
System.out.println("100 " + subsetSum(set, 100, new ArrayList<Integer>()));
System.out.println("9 " + subsetSum(set, 9, new ArrayList<Integer>()));
}
// 1.A
/** This method recursively add the last digit
* to the sum of the rest of the digits.
*/
public static int sumDigits(int n) {
assert n >= 0;
if (n==0){
return 0;
}else {
return (n%10)+ sumDigits(n/10);
}
}
//1.B
/** Recursively sums up the bottom layer of the
* cannonball pyramid
*/
public static int countCannonballs(int height){
assert height >= 0;
if ( height == 0 ){
return 0;
}else {
return height*height + countCannonballs(height -1);
}
}
// 1.C
/** Recursively checks is the first and last
* characters are equal, removes them, and
* checks the resultant string in the same way.
* The 'lazy' && operator insures that if the
* first and last characters are not equal,
* the recursion stops, and the method returns false.
*/
public static boolean isPalindrome(String s){
assert s!=null;
int l = s.length();
if (l == 0 || l == 1) {
return true;
} else {
return (s.charAt(0)==s.charAt(l -1)) &&
isPalindrome(s.substring(1,l-1));
}
}
// 1.D
/** If the string contains: (), {}, [], remove them
* and then figure out if this resultant string
* is balanced, or else return false.
*/
public static boolean isBalanced(String s){
assert (s != null);
if (s.length() == 0){
return true;
} else {
if (! (s.contains("()") ||
s.contains("{}") ||
s.contains("[]")) ){
return false;
} else {
s = s.replaceAll("\\(\\)", "");
s = s.replaceAll("\\{\\}", "");
s = s.replaceAll("\\[\\]", "");
return isBalanced(s);
}
}
}
//2.A
/** To generate all the substrings, split the
* string into a one character long one, and the rest
* then create all the substrings concatenating the 'head' with
* the substrings of the 'rest' String, and add them to the
* accumulation of substrings ( 'result' ).
*/
public static void generateSubstrings(String s, ArrayList<String> result){
assert(s != null && result != null);
if (s.length() == 0){
result.add("");
} else {
String head = s.substring(0,1);
String rest = s.substring(1);
generateSubstrings(rest, result);
ArrayList <String> temp = new ArrayList<String>();
for (int i = 0; i < result.size(); i++){
temp.add( head + result.get(i) );
}
result.addAll (temp);
}
}
//2.B
/** The helper method permuteHelper is needed because
* as the recursion occurs, string accumulation needs to passed
* on. permuteHelper has two strings as parameters that make
* the distinction between characters chosen, and those not.
*/
public static void generatePermutations(String str, ArrayList<String> result){
assert str != null;
permuteHelper("", str, result);;
}
/** The algorithm for evaluating the permutations of a string
* is to have an accumulation variable: 'soFar', and rest,
* and iterating through rest (characters not chosen yet),
* accumulate each character in different cases, and repeat the
* process on the remaining unchosen characters ( 'rest'), until
* there are no more characters to be chosen.
*/
private static void permuteHelper(String soFar, String rest, ArrayList<String> result){
assert(soFar != null && rest != null && result != null);
for (int i = 0; i < rest.length(); i++){
String newSoFar = new String(soFar);
String newRest = "";
int y = 0;
for (int j = 0; j < rest.length(); j++){
if (j != i){
newRest+=rest.charAt(j);
y++;
}
}
newSoFar += rest.charAt(i);
if (newRest.length() == 0){
result.add(newSoFar);
} else {
permuteHelper(newSoFar, newRest, result);
}
}
}
//2.C
/**
* The following two methods act in conjunction
* to convert decimal to binary without trailing
* zeros, but still defined for number=0
*/
public static String toBinary(int number) {
assert number >=0;
if (number == 0){
return "0";
} else {
return toBinaryHelper(number);
}
}
private static String toBinaryHelper(int number){
assert number >=0;
String output = "";
if (number > 0){
output = toBinaryHelper(number/2) + number%2;
}
return output;
}
//2.D
/**
* This method recursively creates all the sums of the subsets
* of the set, and consistently checks whether these sums
* equal the target.
* The sums are created by adding the first integer to all
* the sums from the rest of the integers, and adding those new
* sums to the accumulator: 'result'
*/
public static boolean subsetSum(int[] sets, int targetSum, ArrayList<Integer> result){
assert (sets != null && result != null);
if (sets.length == 0){
if (targetSum == 0){
return true;
} else {
return false;
}
} else if (sets.length == 1){
result.add(sets[0]);
return targetSum == sets[0];
}
else {
int head = sets[0];
int [] rest = cdr(sets);
if (subsetSum (rest, targetSum, result)){
return true;
} else {
ArrayList <Integer> temp = new ArrayList<Integer>();
if (head == targetSum){
return true;
}
temp.add(head);
for (int i = 0; i < result.size(); i++){
if (head + result.get(i) == targetSum){
return true;
}
temp.add( head + result.get(i) );
}
result.addAll (temp);
return false;
}
}
}
/** cdr is the method in LISP meaning:
* return the rest of the list
* excluding the first element*/
private static int[] cdr (int[] input){
assert input != null;
if (input.length <=1){
return null;
} else {
int [] output = new int[input.length-1];
for (int i = 0; i < output.length; i++){
output[i] = input[i+1];
}
return output;
}
}
private static void printArray(ArrayList x) {
System.out.print("[");
for (int i = 0; i < x.size(); i++){
System.out.print(x.get(i) + delimiter);
}
System.out.println("]");
}
}