A goog hint that a problem is recursive is that it can be build off sub-problems.
Bottom-Up Recursion: most intuitive, we start with knowing how to solve the problem for a simple case.
Up-Bottom Recursion: more complex.
Dynamic programming is little more than recursion where you cache the results. A good way to approach such a problem is often to implement it as a normal recursive solution, and then to add the caching part.
9.1 A child is running up a staircase with n steps, and can hop either 1, 2, 3 steps at a time. Implement a method to count how many possible ways the child can run up the stairs.(DP)
1 static int[] buf; 2 public int steps_need(int hight){ 3 if(buf[hight - 1] > 0){ 4 return buf[hight - 1]; 5 } 6 else if(buf[hight - 1] < 0){ 7 System.out.println("overflow"); 8 return -1; 9 } 10 else{ 11 if(hight == 1) buf[hight - 1] = 1; 12 else if(hight == 2) buf[hight - 1] = 2; 13 else if(hight == 3) buf[hight - 1] = 4; 14 else buf[hight - 1] = steps_need(hight - 1) + steps_need(hight - 2) + steps_need(hight - 3); 15 return buf[hight - 1]; 16 } 17 } 18 19 public void pro7(){ 20 int hight = 30; 21 if(hight < 1){ 22 System.out.println("input error"); 23 return; 24 } 25 buf = new int[hight]; 26 int ways = steps_need(hight); 27 System.out.println("ways: "+ ways); 28 }
9.3 A magic index in an array A[0 ... n-1] is defined to be an index such that A[i] = i. Given a sorted array, write a method to find a magic index.
1 public int magicFast(int[] array, int start, int end){ 2 if(end < start || start < 0 || end >= array.length) return -1; 3 int mid = (start + end) / 2; 4 if(array[mid] == mid) return mid; 5 else if(array[mid] > mid) return magicFast(array, start, mid - 1); 6 else return magicFast(array, mid + 1, end); 7 } 8 public int magicFast(int[] array){ 9 return 10 magicFast(array, 0, array.length - 1); 11 }
Follow Up: what if the elements are not distinct?
cannot conclude which side the magic index is on.
The general pattern is that we compare midIndex and midValue for equality first. Then, if they are not equal, we recursively search the left and right sides as follows:
Left side: search indices start through Math.min(minIndex - 1, minValue)
Right side: search indices Math.max(midIndex + 1, midValue) through end.
But this can only return one of the results, if there exists many results.
1 public int magicFast(int[] array, int start, int end){ 2 if(end < start || start < 0 || end > array.length) return -1; 3 int midIndex = (start + end) / 2; 4 int midValue = array[midIndex]; 5 if(midValue == midIndex) return midIndex; 6 7 //search left 8 int leftIndex = Math.min(midIndex - 1, midValue); 9 int left = magicFast(array, start, leftIndex); 10 if(left >= 0) return left; 11 //search right 12 int rightIndex = Math.max(midIndex + 1, midValue); 13 int right = magicFast(array, rightIndex, end); 14 return right; 15 } 16 public int magicFast(int[] array){ 17 return magicFast(array, 0, array.length - 1); 18 }
9.4 Write a method to return all subsets of a set.
1 ArrayList<ArrayList<Integer>> getSubset(ArrayList<Integer> set){ 2 ArrayList<ArrayList<Integer>> results = new ArrayList<ArrayList<Integer>>(); 3 int max = 1 << set.size(); 4 for(int k = 0; k < max; k ++){ 5 ArrayList<Integer> subset = convert(k, set); 6 results.add(subset); 7 } 8 return results; 9 } 10 ArrayList<Integer> convert(int x, ArrayList<Integer> set){ 11 ArrayList<Integer> result = new ArrayList<Integer>(); 12 int index = 0; 13 for(int k = x; k > 0; k >>= 1){ 14 if((k & 1) == 1) result.add(set.get(index)); 15 index ++; 16 } 17 return subset; 18 }