Saturday, May 28, 2016
Tuesday, May 24, 2016
Big O notation and visualization
Most of time algorithm performance is measured by time complexity . Space complexity is also important but it is compromised most of time . If space required is not much compared to modern hardware then it can be ignored .
In computer science when there are two or more ways or algorithms to solve the problem we need to choose best one which completes in less time .
Practical way is ,for same hardware , for same size , run algorithms , use e.g. System.nanoTime() to measure time then compare them together . We might need to run experiment for all possible sizes .
Instead of writing all possible approaches and measuring time for actual scenarios is time consuming.
Is there any other way for such comparison of algorithms ?
Yes there is which uses asymptotic notation called Big_O_notation .
Big O notation denoted maximum time taken by algorithm for given size of problem .
It is asymptotic (tangent at infinity) upper bound.
f(n) = O(g(n)) and if there exists constant c and n0 such that
f(n) <= c*g(n) for n >= n0
f(n) , g(n) are functions over non-negative integers .
Big O notation is used for worst case analysis of algorithms .
Instead of calculating actual time , it measures growth of time with growth of the problem size .
Every time size of problem increases , time is bound to increase .
Example : To find maximum element in array using scanning is O(n) means as size of array increases we will need more time to find the maximum element . Say maximum element is located at end . If array size is of 10 then it takes 10 mSecs to find the element . If array size if 10 million then time requires could be 100 secs which is 1.5 min . if array size is of 1 billion then it will be 1500 min which is too large .
If say 1 Billion array is circularly sorted and we use binary search for the problem which is O(log(n)) then time required will be 20 mSec which is very fast .
So if we have efficient algorithm then on even commodity machine we can give fast outputs.
To calculate "Big O notation" we need to consider only higher order terms .
Example :
n^2 + 4n+3 is O(n^2)
nlog2(n) + 10n + 1 is O(nlog2(n))
Asymptotic running time by comparison n --> infinity
1 < log2(n) < n < nlog2(n) < n^2 < 2^n
Theta (asymptotically tight bound ) , Ohh (upper bound ) and Omega (lower bound) notation differences
Figure (a) : Theta notation consider theta function sandwiching actual function by upper and lower bounds
Figure (b) : Oh notation consider it as equal or upper bound or worst case
Figure (c) : Omega notation is function which confines equal or lower bounds. consider it as best case where time required is less.
little Ohh notation is strictly above the function .
little Omega is strictly below the function .
e.g. Insertion sort for already sorted array Theta is between n^2 and n so big ohh is n^2 and omega is n only.
Most of time you will check big ohh notation because we are interested in worst case performance .
Graph of T(n) = O(g(n))
From left to right (Y axis to X)
O(2^n), O(n^2) , O(n*log2(n)) ,O(n) , O(sqrt(n)) , O(log2(n))
Slowest growth of time for given input is O(log2(n)) .
Legends
Y - time in secs to execute the algorithm
X - number of items as input to algorithm
Selection of algorithm for sorting
Sorting is the fundamental operation in computer science .
Choice of sorting algorithm depends on
- Number of items to be sorted
- Number of items already somewhat sorted
- Possible restrictions on item values like comparing operation
- Computer architecture like number of CPUs , IO speed , main memory , disk space
- Nature of computing multi-threaded or parallel distributed
- Stability of sort
- Is there need for extra space or in-place sort ?
- Is multi-algorithm sort optimization strategy needed ? example - if size of merge sort say below 30-40 then use insertion sort else use merge sort during divide phase of the algorithm .
- Ease of implementation. example - in-place merge sort implementation is theoretically possible but extremely difficult for practical purposes .
Comparison of algorithms
In practice best algorithm is heap sort because it is in-place and running time is on par with merge sort .
But biggest disadvantage of heap sort is it is not stable sort .
So when there is no requirement of stability use heap sort else use merge sort in combination with insertion sort (for size of 30-40 ) .
Thursday, May 19, 2016
Search element in circularly sorted array .(Java Code)
Problem : Search index of element in circularly sorted array . Elements are not repeated.
Observations :
Whenever array is sorted always look out for usage of binary search for best worst performance .
Scanning array
Iterate over array and just look for element once we get break the loop.
Time complexity , T(n) = n
Tweaked binary search
Sorted array --> 1,2,3,4,5,6,7,8,9,10,11
intput -->
After one rotation --> 11,1,2,3,4,5,6,7,8,9,10
if we are searching for 9
Output --> 8
For mid pivot ( ( high+low )/2) of 5 right half is sorted . while left is not sorted .
So for any rotation one half will be sorted and other will not be .
Based on this fact we need to direct binary search to the part of circular array .
Time complexity , T(n) = log2(n)
Java Code
Observations :
Whenever array is sorted always look out for usage of binary search for best worst performance .
Scanning array
Iterate over array and just look for element once we get break the loop.
Time complexity , T(n) = n
Tweaked binary search
Sorted array --> 1,2,3,4,5,6,7,8,9,10,11
intput -->
After one rotation --> 11,1,2,3,4,5,6,7,8,9,10
if we are searching for 9
Output --> 8
For mid pivot ( ( high+low )/2) of 5 right half is sorted . while left is not sorted .
So for any rotation one half will be sorted and other will not be .
Based on this fact we need to direct binary search to the part of circular array .
Time complexity , T(n) = log2(n)
Java Code
package com.salpe.sort; import org.junit.Assert; import org.junit.Test; public class BinarySearchUtils { @Test public void testSuccess() { int[] arr = new int[] {1,2,3,4,5,6,7,8,9,10,11}; Assert.assertEquals(4, searchCircularArray(arr, 5)); arr = new int[] {11,1,2,3,4,5,6,7,8,9,10}; Assert.assertEquals(5, searchCircularArray(arr, 5)); arr = new int[] {10,11,1,2,3,4,5,6,6,7,8,9}; Assert.assertEquals(6, searchCircularArray(arr, 5)); } /** * <p> * mid always divides array between one sorted and one unsorted sub arrays. * * <p> * array rotated by 2 --> 11,10,1,2,3,4,5,6,7,8,9 * <p> * mid element is 4 left of 4 is not sorted , right of 4 is sorted * * <p> * If it is sorted then check lo and hi to check value in it else go to * other unsorted half. * <p> * * T(n) = log2(n) * * @param arr * @param val * @return */ public static int searchCircularArray(int[] arr, int val) { int lo = 0; int hi = arr.length - 1; while (lo <= hi) { // find mid pivot int mid = (lo + hi) / 2; // if mid matches game over if (arr[mid] == val) { return mid; } // right array sorted else if (arr[mid] < arr[hi]) { // check value contains in sorted right if (val > arr[mid] && val <= arr[hi]) { lo = mid + 1; } else { hi = mid - 1; } } // left array sorted else { // check value contains in sorted left if (val < arr[mid] && val >= arr[lo]) { hi = mid - 1; } else { lo = mid + 1; } } } // oops no match found return -1; } }
Monday, May 16, 2016
Tracing a recursive function .
Observations :
Problem : Find the values of n printed to console .
public static void function123(int n){ if(n<=0){ return; } System.out.println(n); function123(n-2); function123(n-3); System.out.println(n); }
Solution :
Problem : Find the values of n printed to console .
static int fib( int n ) { if ( n == 0 ) // base case 1 return 1; else if ( n == 1 ) // base case 2 return 2; else { int resultA = fib( n - 1 ); // "A" int resultB = fib( n - 2 ); // "B" System.out.println(resultA+resultB); return resultA + resultB; } }
Solution :
Problem : Trace the path of recursion
public int searchWithR(int[] arr, int value, int lo, int hi) { // exit condition if (lo > hi) { // return special value if term is not found; return -1; } int mid = (lo + hi) / 2; if (arr[mid] == value) { return mid; } else if (value < arr[mid]) { // change value of high , one position left of mid return searchWithR(arr, value, lo, mid - 1); } else { // change value of low , one position right of mid return searchWithR(arr, value, mid + 1, hi); } }
Binary search on sorted array (Java Code)
Problem - What is efficient way to search a sorted array .
Observations :
For searching an element in the array strategy depends on nature of data in array .
Binary is search is well known divide and conquer algorithm .
It can be implemented using recursion or without recursion using stack .
Algorithm Complexity : worst case Ω(log2(n)) , average case O(log2(n)) , best case O(1) .
Sequential Search for sorted array
To search 7th place we have to traverse to 7 places. which proves complexity O(n) .
Binary Search for sorted array
To search 7th place , we have to traverse 3 places . which proves complexity O(log2(n)).
Java Code
Observations :
For searching an element in the array strategy depends on nature of data in array .
- If array is not sorted there is no other way than sequential scan of the array .
- If array is sorted but length is not known then jump search ( jump with constant size or Fibonacci number or exponential factor ) could be used to improve sequential scan .
- If array is sorted and length is known then binary search is best way to do the search .
Binary is search is well known divide and conquer algorithm .
It can be implemented using recursion or without recursion using stack .
Algorithm Complexity : worst case Ω(log2(n)) , average case O(log2(n)) , best case O(1) .
Sequential Search for sorted array
To search 7th place we have to traverse to 7 places. which proves complexity O(n) .
Binary Search for sorted array
To search 7th place , we have to traverse 3 places . which proves complexity O(log2(n)).
Java Code
package com.salpe.arrays; import org.junit.Assert; import org.junit.Test; public class BinarySearchUtils { @Test public void testSuccess() { int[] arr = new int[] { 0, 1, 2, 3, 4, 5, 6, 7, 8 }; int result1 = searchWithR(arr, 7, 0, arr.length - 1); Assert.assertEquals(result1, 7); int result2 = searchWithoutR(arr, 7, 0, arr.length - 1); Assert.assertEquals(result2, 7); } public int searchWithR(int[] arr, int value, int lo, int hi) { // exit condition if (lo > hi) { // return special value if term is not found; return -1; } int mid = (lo + hi) / 2; if (arr[mid] == value) { return mid; } else if (value < arr[mid]) { // change value of high , one position left of mid return searchWithR(arr, value, lo, mid - 1); } else { // change value of low , one position right of mid return searchWithR(arr, value, mid + 1, hi); } } public int searchWithoutR(int[] arr, int value, int lo, int hi) { // condition to check less than or equal* is very important while (lo <= hi) { int mid = (lo + hi) / 2; if (arr[mid] == value) { return mid; } else if (value < arr[mid]) { // change value of high , one position left of mid hi = mid - 1; } else { // change value of low , one position right of mid lo = mid + 1; } } // return is case no result found return -1; } }
Sunday, May 15, 2016
Binary Search Tree : Check whether given binary tree is binary search tree or not .
Problem :
Check whether given binary tree is binary search tree or not.
Observation :
Binary Tree - tree with maximum two leaves .
Binary search tree (BST) - tree with maximum two leaves such that (left < root < right ) leaf.
For binary tree to be as binary search tree properties are
1. left sub-tree must be less than root .
2. right sub-tree must be greater than root.
3. Means value of root must lie between limits of left and right values .
Or
1. If we do in-order traversal of the tree it must give values sorted in ascending order
Algorithm Type : Recursion
Java code using above two properties
package com.salpe.tree; import java.util.logging.Logger; import org.junit.Assert; import org.junit.Test; /** * Check whether given binary tree is binary search tree or not * */ public class BSTTest5 { private static final Logger s_logger = Logger.getLogger(BSTTest2.class.getName()); /** * Binary tree pre-order list as 0,1,2,3,4,5,6 */ @Test public void testSuccess() { BST<Integer> bst = createSuccessTestData(); boolean resultSubBSTChk = bst.isBSTUsingSubBSTChk(); boolean resultInorderChk = bst.isBSTUsingInorderChk(); s_logger.info("Using subSBTChk: " + Boolean.toString(resultSubBSTChk)); s_logger.info("using InorderChk: " + Boolean.toString(resultInorderChk)); Assert.assertTrue(resultSubBSTChk); Assert.assertTrue(resultInorderChk); } /** * tests when binary search tree is degraded to linked list */ @Test public void testWorstCaseSuccess() { BST<Integer> bst = createSuccessWorstCaseTestData(); boolean resultSubBSTChk = bst.isBSTUsingSubBSTChk(); boolean resultInorderChk = bst.isBSTUsingInorderChk(); s_logger.info("Using subSBTChk: " + Boolean.toString(resultSubBSTChk)); s_logger.info("using InorderChk: " + Boolean.toString(resultInorderChk)); Assert.assertTrue(resultSubBSTChk); Assert.assertTrue(resultInorderChk); } @Test public void testFailure() { BST<Integer> bst = createFailureTestData(); boolean resultSubBSTChk = bst.isBSTUsingSubBSTChk(); boolean resultInorderChk = bst.isBSTUsingInorderChk(); s_logger.info("Using subSBTChk: " + Boolean.toString(resultSubBSTChk)); s_logger.info("using InorderChk: " + Boolean.toString(resultInorderChk)); Assert.assertFalse(resultSubBSTChk); Assert.assertFalse(resultInorderChk); } private BST<Integer> createSuccessTestData() { // create test data BSTNode<Integer> node0 = new BSTNode<>(0, null, null); BSTNode<Integer> node2 = new BSTNode<>(2, null, null); BSTNode<Integer> node01 = new BSTNode<>(1, node0, node2); BSTNode<Integer> node06 = new BSTNode<>(6, null, null); BSTNode<Integer> node04 = new BSTNode<>(4, null, null); BSTNode<Integer> node05 = new BSTNode<>(5, node04, node06); BSTNode<Integer> node03 = new BSTNode<>(3, node01, node05); // create BST BST<Integer> bst = new BST<>(node03); return bst; } /** * worst case is linked list for binary tree * * @return */ private BST<Integer> createSuccessWorstCaseTestData() { // create test data BSTNode<Integer> node06 = new BSTNode<>(6, null, null); BSTNode<Integer> node05 = new BSTNode<>(5, null, node06); BSTNode<Integer> node04 = new BSTNode<>(4, null, node05); BSTNode<Integer> node03 = new BSTNode<>(3, null, node04); BSTNode<Integer> node02 = new BSTNode<>(2, null, node03); BSTNode<Integer> node01 = new BSTNode<>(1, null, node02); BSTNode<Integer> node0 = new BSTNode<>(0, null, node01); // create BST BST<Integer> bst = new BST<>(node0); return bst; } private BST<Integer> createFailureTestData() { // create test data BSTNode<Integer> node0 = new BSTNode<>(0, null, null); BSTNode<Integer> node2 = new BSTNode<>(2, null, null); BSTNode<Integer> node01 = new BSTNode<>(1, node0, node2); BSTNode<Integer> node06 = new BSTNode<>(-600, null, null); BSTNode<Integer> node04 = new BSTNode<>(4, null, null); BSTNode<Integer> node05 = new BSTNode<>(5, node04, node06); BSTNode<Integer> node03 = new BSTNode<>(3, node01, node05); // create BST BST<Integer> bst = new BST<>(node03); return bst; } /** * Binary Tree Node model * * @param <T> */ static class BSTNode<T extends Comparable<T>> { T data; BSTNode<T> left; BSTNode<T> right; BSTNode(T data, BSTNode<T> left, BSTNode<T> right) { this.data = data; this.left = left; this.right = right; } @Override public String toString() { return "BSTNode [data=" + data + "]"; } } /** * Binary Tree Representation * * @param <T> */ static class BST<T extends Comparable<T>> { BSTNode<T> root; public BST(BSTNode<T> root) { this.root = root; } boolean isBSTUsingSubBSTChk() { return isBSTUsingSubBSTChk0(root); } /** * @param root * @return whether binary tree is BST */ private boolean isBSTUsingSubBSTChk0(BSTNode<T> root) { if (root == null) { return true; } if ((root.left != null && (root.data.compareTo(root.left.data) < 0)) || ((root.right != null) && (root.data.compareTo(root.right.data) > 0))) { return false; } // left part is BST boolean isLeftBST = isBSTUsingSubBSTChk0(root.left); // right part is BST boolean isRightBST = isBSTUsingSubBSTChk0(root.right); // left , middle , right is BST if all are BST return isLeftBST && isRightBST; } boolean isBSTUsingInorderChk() { return isBSTUsingInorderChk0(root, null); } private boolean isBSTUsingInorderChk0(BSTNode<T> node, T prev) { if (node == null) { return true; } boolean leftPartInorder = isBSTUsingInorderChk0(node.left, prev); boolean isleftBeforeRight = (prev != null ? prev.compareTo(node.data) < 0 : true); boolean rightPartInorder = isBSTUsingInorderChk0(node.right, node.data); return leftPartInorder && isleftBeforeRight && rightPartInorder; } } }
Saturday, May 14, 2016
Iterate over Binary Search Tree (BST) - DepthFirst (preOrder, inOrder, postOrder ) , breadthFirst (Java Code)
Problem :
Traverse over binary search tree.
Solution -
Lets take very simple tree with 2 as root and left as 1 and right as 2.
Depth First : Traverse through columns/vertical . For very big binary search tree such traversal could be time consuming .
Goes to farthest left node then traverse remaining and then go to farthest right node .
Pre-Order traversal = 2,1,3
In-Order traversal = 1,2,3 (it is always sorted list in ascending order.)
Post-Order traversal = 1,3,2
Same logic will apply for any BST with any number of nodes .
Typically these are recursive functions otherwise stack is used to implement non-recursive functions.
It will be same logic for binary tree and graph .
Breath First :
Typically it is implemented using queue .
Traverse through rows/horizontal . For very big binary tree optimization could be done like after 100th level ignore next levels etc .
Traverse one level distance away in each recursion .
It will be same logic for binary tree and graph .
level by level traversal = 2,1,3 or 2,3,1
Same logic will apply for any BST with any number of nodes .
package com.salpe.tree; import java.util.Iterator; import java.util.LinkedList; import java.util.logging.Logger; import org.junit.Test; import com.salpe.tree.BSTUtils.BST.IteratorType; /** * Binary tree could be traversed in two ways * 1. Depth First * a) pre-order * b) in-order * c) post-order * <p> * 2. Breadth First - level by level * </p> * */ public class BSTUtils { // logger private static final Logger s_logger = Logger.getLogger(BSTUtils.class.getName()); // Binary tree node model static class BST<T extends Comparable<T>> { public enum IteratorType { PRE_ORDER, IN_ORDER, POST_ORDER, BREATH_FIRST; } private BSTNode<T> root; private int length; public void add(T data) { if (root == null) { root = new BSTNode<T>(data, null, null); } else { add0(root, data); } } /** * BST shape depends on order of insertion - not optimized for re-balancing * @param node * @param data * @return added node */ private BSTNode<T> add0(BSTNode<T> node, T data) { if (node == null) { length++; return new BSTNode<T>(data, null, null); } if (data.compareTo(node.id) < 0) { node.left = add0(node.left, data); } else if (data.compareTo(node.id) > 0) { node.right = add0(node.right, data); } else { return node; } return node; } /** * For searching binary tree must be binary search tree. * * @param data * @return searched node */ public BSTNode<T> search(T data) { BSTNode<T> start = root; while (start != null) { if (data.compareTo(start.id) < 0) { start = start.left; } else if (data.compareTo(start.id) > 0) { start = start.right; } else { return start; } } return null; } /** * Iterator design pattern . * But it is eager fetching so not true iterator design pattern * * @param type * @return Iterator */ public Iterator<T> iterator(IteratorType type) { LinkedList<T> list = new LinkedList<>(); switch (type) { case PRE_ORDER: preOrderTraversal(root, list); break; case IN_ORDER: inOrderTraversal(root, list); break; case POST_ORDER: postOrderTraversal(root, list); break; case BREATH_FIRST: breadthFirstTraveral(root, list); default: break; } return list.iterator(); } /** * first visit left then current then right node. * Could be converted in non-recursive function using stack * @param node * @param list */ private void inOrderTraversal(BSTNode<T> node, LinkedList<T> list) { if (node == null) { return; } inOrderTraversal(node.left, list); list.add(node.id); inOrderTraversal(node.right, list); } /** * first visit current then left and then right node. * Could be converted in non-recursive function using stack * @param node * @param list */ private void preOrderTraversal(BSTNode<T> node, LinkedList<T> list) { if (node == null) { return; } list.add(node.id); preOrderTraversal(node.left, list); preOrderTraversal(node.right, list); } /** * first visit left then current and then right node * Could be converted in non-recursive function using stack * @param node * @param list */ private void postOrderTraversal(BSTNode<T> node, LinkedList<T> list) { if (node == null) { return; } postOrderTraversal(node.left, list); postOrderTraversal(node.right, list); list.add(node.id); } /** * Level by level traversal using queue * * @param node * @param list */ private void breadthFirstTraveral(BSTNode<T> node, LinkedList<T> list) { LinkedList<BSTNode<T>> queue = new LinkedList<>(); queue.offer(node); while (queue.size() != 0) { BSTNode<T> nodeToVisit = queue.poll(); list.add(nodeToVisit.id); if (nodeToVisit.left != null) queue.offer(nodeToVisit.left); if (nodeToVisit.right != null) queue.offer(nodeToVisit.right); } } } /** * Binary tree model can used as BST also * * @param <T> */ static class BSTNode<T extends Comparable<T>> { private T id; private BSTNode<T> left; private BSTNode<T> right; public BSTNode(T id, BSTNode<T> left, BSTNode<T> right) { super(); this.id = id; this.left = left; this.right = right; } @Override public String toString() { return "BSTNode [id=" + id + "]"; } } @Test public void test() { // create empty BST BST<Integer> bst = new BST<>(); // add nodes bst.add(4); bst.add(2); bst.add(5); bst.add(1); bst.add(3); bst.add(6); bst.add(7); // binary search tree in-order representation is 1,2,3,4,5,6,7 where // root is 4 print(IteratorType.PRE_ORDER, bst.iterator(IteratorType.PRE_ORDER)); print(IteratorType.IN_ORDER, bst.iterator(IteratorType.IN_ORDER)); print(IteratorType.POST_ORDER, bst.iterator(IteratorType.POST_ORDER)); print(IteratorType.BREATH_FIRST, bst.iterator(IteratorType.BREATH_FIRST)); } private static void print(IteratorType type, Iterator<Integer> itr) { StringBuilder bld = new StringBuilder(type.name()).append(" ---> "); while (itr.hasNext()) { bld.append(itr.next()).append(" ,"); } s_logger.info(bld.toString()); } }
Find maximum height or depth of binary tree. (Java Code)
Problem : Find the height of binary tree where tree might or might be complete .
Observations :
For complete BST
height = at most log2(total number of nodes)
or
h = long2(n)
So it is straight forward no traversal is needed , But if tree is not complete then we need to find height of all the leaves and get maximum out of it .
We need to store only max value at any given time . Means we do not need caching of heights for each leaf..
We need to use depth first recursion as we need to calculate depth or height .
Algorithm Class : Recursion - back tracking
Java Code
Observations :
For complete BST
height = at most log2(total number of nodes)
or
h = long2(n)
So it is straight forward no traversal is needed , But if tree is not complete then we need to find height of all the leaves and get maximum out of it .
We need to store only max value at any given time . Means we do not need caching of heights for each leaf..
We need to use depth first recursion as we need to calculate depth or height .
Algorithm Class : Recursion - back tracking
Java Code
package com.salpe.tree; import java.util.logging.Logger; import org.junit.Test; /** * Find maximum height/depth of binary tree * Algorithm will be same for binary tree or binary search tree. */ public class BSTTest3 { // logger private static final Logger s_logger = Logger.getLogger(BSTTest2.class.getName()); /** * Binary search tree pre-order list as 0,1,2,3,4,5,6 */ @Test public void test() { // create test data BSTNode<Integer> node0 = new BSTNode<>(0, null, null); BSTNode<Integer> node2 = new BSTNode<>(2, null, null); BSTNode<Integer> node01 = new BSTNode<>(1, node0, node2); BSTNode<Integer> node06 = new BSTNode<>(6, null, null); BSTNode<Integer> node04 = new BSTNode<>(4, null, null); BSTNode<Integer> node05 = new BSTNode<>(5, node04, node06); BSTNode<Integer> node03 = new BSTNode<>(3, node01, node05); // create BST BST<Integer> bst = new BST<>(node03); int maxHeight = bst.findMaxHeight(); s_logger.info(Integer.toString(maxHeight)); } /** * Binary Tree Node model * @param <T> */ static class BSTNode<T extends Comparable<T>> { T data; BSTNode<T> left; BSTNode<T> right; BSTNode(T data, BSTNode<T> left, BSTNode<T> right) { this.data = data; this.left = left; this.right = right; } @Override public String toString() { return "BSTNode [data=" + data + "]"; } } /** * Binary Tree Representation * * @param <T> */ static class BST<T extends Comparable<T>> { BSTNode<T> root; public BST(BSTNode<T> root) { this.root = root; } /** * @return max height or max depth of balanced or unbalanced binary * tree. */ public int findMaxHeight() { return depthFirstSearch0(root, 0); } /** * Need to traverse all tree because right/left most side might be max * length problem could be solved using dynamic programming also by * caching latest maximum height * * @param node * - root * @param currentHeight * @return maximum height of binary search tree. */ public int depthFirstSearch0(BSTNode<T> node, int currentHeight) { if (node == null) { return currentHeight; } // increase height by 1 for increase in depth for recursion stack currentHeight++; // go left int leftMaxHeight = depthFirstSearch0(node.left, currentHeight); // then go right int rightMaxheight = depthFirstSearch0(node.right, currentHeight); // decrease height by 1 for decrease in depth for recursion stack currentHeight--; return Math.max(leftMaxHeight, rightMaxheight); } } }
Find index of first one in series/array of zeros and ones where all zeros comes always before all ones. (Java Code )
Search/Find index of first one in series/array of zeros and ones where all zeros comes always before all ones.
At least one is guaranteed in the series .
Length of array /series is not known .
Example :
Input :
01111111111111111111111111111..... length is not known
output : 1
Input :
00000000000000000000000011111111111.... length is not known
output : 25
Observations :
- Array is sorted .
- You can not use binary search as length is not known .
- Only option remains is sequential scan of zeros till first one is met .whose complexity will be O(n)
- There is zero before one which we are interested .
- Index of one is lowest which we are interested .
How to improve it ?
Lets say take random number or jump size as 10 .
Lets jump by 10 till you get first one . then always move to left with half of jum distance till you get 1 . Which ill be answer.
If we get ArrayIndexOutOfBoundException then opt for sequential search .
Best case solution could be of complexity (number of jumps + log2( jump size)) ~ O(n) but better than previous O(n) .
Jump size could optimized based on data if you have large number of zeros then take jump size large else something like 10 . This is data driven optimization .
This typical case of jump search for array or skip list search .
There could be two flavors of problem say one with no length known other could be with known length is array .
Solution in java (length is not known )
package com.salpe.arrays; import org.junit.Assert; import org.junit.Test; public class BinarySearchUtils { /** * Jump size is less than array size */ @Test public void testSuccess1() { int[] arr = new int[] { 0, 0, 0, 0, 0, 0, 0, 0, 1 }; int result1 = search(arr); Assert.assertEquals(8, result1); } /** * Jump size is equal to array size */ @Test public void testSuccess2() { int[] arr = new int[] { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 }; int result1 = search(arr); Assert.assertEquals(10, result1); } /** * Jump size is less than array size */ @Test public void testSuccess3() { int[] arr = new int[] { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 }; int result1 = search(arr); Assert.assertEquals(17, result1); } /** * Say length of array is not known Complexity is lon2(n) * * @param arr * @return */ public int search(int... arr) { // first decide possible segment // Jumping forth and back as per figure till we hit first one . // jump size depends on data , optimization is data dependent int jump = 10; int hi = 0; int lo = 0; int hiVal = -1; while (lo <= hi) { try { // jump forward hi = lo + jump; // test for out of index or NaN value hiVal = arr[hi]; } catch (ArrayIndexOutOfBoundsException arrayIndexOutOfBoundsException) { // jump half back jump = jump / 2; continue; } if (hiVal == 1) { break; } lo = hi; } // binary search between segment of possible size segment , segment/2 , // segment/4 and so on return searchWithNoRecursion(arr, 1, lo, hi); } public int searchWithNoRecursion(int[] arr, int value, int lo, int hi) { while (lo <= hi) { int mid = (lo + hi) / 2; if (arr[mid] == value) { if (mid == 0) { return 0; } if (arr[mid - 1] == 0) { return mid; } else { hi = mid - 1; } } else { lo = mid + 1; } } // return is case no result found return -1; } public int searchWithRecursion(int[] arr, int value, int lo, int hi) { // exit condition if (lo > hi) { // return special value if term is not found; return -1; } int mid = (lo + hi) / 2; if (arr[mid] == value) { if (mid == 0) { return 0; } if (arr[mid - 1] == 0) { return mid; } else { return searchWithRecursion(arr, value, lo, mid - 1); } } else if (value < arr[mid]) { return searchWithRecursion(arr, value, lo, mid - 1); } else { return searchWithRecursion(arr, value, mid + 1, hi); } } }
Solution in java (length is known )
package com.salpe.arrays; import org.junit.Assert; import org.junit.Test; public class BinarySearchUtils { @Test public void testSuccess1() { int[] arr = new int[] { 0, 0, 1, 1, 1 }; int result1 = searchWithNoRecursion(arr, 1, 0, arr.length - 1); int result2 = searchWithRecursion(arr, 1, 0, arr.length - 1); Assert.assertEquals(2, result1); Assert.assertEquals(2, result2); } @Test public void testSuccess2() { int[] arr = new int[] { 0, 0, 0, 0, 1 }; int result1 = searchWithNoRecursion(arr, 1, 0, arr.length - 1); int result2 = searchWithRecursion(arr, 1, 0, arr.length - 1); Assert.assertEquals(4, result1); Assert.assertEquals(4, result2); } @Test public void testSuccess3() { int[] arr = new int[] { 1, 1, 1, 1, 1 }; int result1 = searchWithNoRecursion(arr, 1, 0, arr.length - 1); int result2 = searchWithRecursion(arr, 1, 0, arr.length - 1); Assert.assertEquals(0, result1); Assert.assertEquals(0, result2); } public int searchWithNoRecursion(int[] arr, int value, int lo, int hi) { while (lo <= hi) { int mid = (lo + hi) / 2; if (arr[mid] == value) { if (mid == 0) { return 0; } if (arr[mid - 1] == 0) { return mid; } else { hi = mid - 1; } } else { lo = mid + 1; } } // return is case no result found return -1; } public int searchWithRecursion(int[] arr, int value, int lo, int hi) { // exit condition if (lo > hi) { // return special value if term is not found; return -1; } int mid = (lo + hi) / 2; if (arr[mid] == value) { if (mid == 0) { return 0; } if (arr[mid - 1] == 0) { return mid; } else { return searchWithRecursion(arr, value, lo, mid - 1); } } else if (value < arr[mid]) { return searchWithRecursion(arr, value, lo, mid - 1); } else { return searchWithRecursion(arr, value, mid + 1, hi); } } }
Find all paths with specified sum in binary tree. (Java code)
package com.salpe; import java.util.ArrayList; import java.util.Collection; import java.util.List; import java.util.logging.Logger; import org.junit.Test; public class BSTTest2 { private static final Logger s_logger = Logger.getLogger(BSTTest2.class.getName()); /** * Binary tree pre-order list as 0,1,2,3,4,5,6 */ @Test public void test() { // create test data BSTNode<Integer> node0 = new BSTNode<>(0, null, null); BSTNode<Integer> node2 = new BSTNode<>(2, null, null); BSTNode<Integer> node01 = new BSTNode<>(1, node0, node2); BSTNode<Integer> node06 = new BSTNode<>(6, null, null); BSTNode<Integer> node04 = new BSTNode<>(4, null, null); BSTNode<Integer> node05 = new BSTNode<>(5, node04, node06); BSTNode<Integer> node03 = new BSTNode<>(3, node01, node05); // create BST BST<Integer> bst = new BST<>(node03); Collection<List<Integer>> result = bst.findAllPaths(12); for (List<Integer> list : result) { s_logger.info(list.toString()); } } /** * Binary Tree Node model * * @param <T> */ static class BSTNode<T extends Comparable<T>> { T data; BSTNode<T> left; BSTNode<T> right; BSTNode(T data, BSTNode<T> left, BSTNode<T> right) { this.data = data; this.left = left; this.right = right; } @Override public String toString() { return "BSTNode [data=" + data + "]"; } } /** * Binary Tree Representation * * @param <T> */ static class BST<T extends Comparable<T>> { BSTNode<T> root; public BST(BSTNode<T> root) { this.root = root; } public Collection<List<T>> findAllPaths(int sum) { List<T> paths = new ArrayList<>(); Collection<List<T>> result = new ArrayList<>(); depthFirstSearch0(root, 0, sum, paths, result); return result; } public void depthFirstSearch0(BSTNode<T> node, int currentSum, int expectedSum, List<T> paths, Collection<List<T>> result) { if (node == null) { return; } paths.add(node.data); // check sum currentSum = currentSum + Integer.parseInt(node.data.toString()); if (currentSum == expectedSum) { // add cloned list result.add(new ArrayList<>(paths)); } // go left depthFirstSearch0(node.left, currentSum, expectedSum, paths, result); // then go right depthFirstSearch0(node.right, currentSum, expectedSum, paths, result); // remove when going up in level paths.remove(paths.size() - 1); } } }
Subscribe to:
Posts (Atom)