Wednesday, 26 November 2014

Meet the robots

Problem:
Two robots land with their parachutes on an infinite one-dimensional number line. They both release their parachutes as soon as they land and start moving. They are allowed only to make use of the following functions.
I.   moveLeft() // robot moves to left by 1 unit in 1 unit time
II.  moveRight() // robot moves to right by 1 unit in 1 unit time
III. noOperation() // robot does not move and takes 1 unit time
IV.  onTopOfParachute() // returns true if the robot is standing on top of either of the parachute, else false
V.   didWeMeet() // returns true if the robot meets to the other robot, else false
Write a function in order to make the robots meet each other. Robots will be executing the same copy of this function.
Solution:
void meetRobots(Robot r1,Robot r2) {
       r1.moveLeft(), r2.moveLeft();
       while(!r1.onTopOfParachute() && !r2.onTopOfParachute()) {
           r1.moveLeft(), r2.moveLeft();
       }
       if(r1.onTopOfParachute()) {
           while(!r2.didWeMeet()) {
               r2.moveRight(),r1.noOperation();
           }
        } else {
           while(!r1.didWeMeet()) {
               r1.moveRight(),r2.noOperation();
           }
        }
           

There is a N*N integer matrix Arr[N][N]. From the row r and column c, we can go to any of the following three indices: (r+1,c-1), (r+1,c) or (r+1,c+1). Find the maximum sum that can be generated from any path starting from any column in first row

Problem:
There is a N*N integer matrix Arr[N][N]. From the row r and column c, we can go to any of the following three indices:
I.                Arr[ r+1 ][ c-1 ] (valid only if c-1>=0)
II.               Arr[ r+1 ][ c ]
III.              Arr[ r+1 ][ c+1 ] (valid only if c+1<=N-1)
So if we start at any column index on row 0, what is the largest sum of any of the paths till row N-1.
Solution
Solution below is O(n^2) solution. We will update all array entries. Starting from last row and moving till first row. Each array entry will be maximum sum that can be generated when starting from that point. At the end we will find entry in first row that has maximum value.

Pseudo code:
void calculateSum(int[][] a,int n,int row) {
       if(row == n-1) {
           return;
       }
       calculateSum(a,n,row+1);
       for(int j=0;j<n;j++) {
           // calculate a[row][j]
           int max = a[row+1][j];
           if(j-1 >=0 && a[row+1][j-1] > max) {
                 max = a[row+1][j-1];
           }
           if(j+1 <= n-1 && a[row+1][j+1] > max) {
                 max = a[row+1][j+1];
           }
           a[row][j] += max;
        }
 }

void maxSumPath(int[][] a,int n) {
      calculateSum(a,n,0);
      int max = a[0][0];
      for(int j=1;j<n;j++) {
          if(a[0][j] > max)max = a[0][j];
      }
      System.out.println(max);
        

There is a binary tree of size N. All nodes are numbered between 1-N(inclusive). There is a N*N integer matrix Arr[N][N], all elements are initialized to zero. So for all the nodes A and B, put Arr[A][B] = 1 if A is an ancestor of B (NOT just the immediate ancestor).

Problem:
There is a binary tree of size N. All nodes are numbered between 1-N(inclusive). There is a N*N integer matrix Arr[N][N], all elements are initialized to zero. So for all the nodes A and B, put Arr[A][B] = 1 if A is an ancestor of B (NOT just the immediate ancestor).

Solution:

The below solution is O(n^2) solution. Each array entry is visited exactly once.

The basic idea is to make current node ancestor for all the nodes except for itself and it's own ancestors.

For any node, it's own ancestors  are maintained in set.
Pseudo code:

void fill(int[][] a,int n, Node root,Set<Integer> parents) {
     if(root == null)return;
     for(int j=0;j<n;j++) {
        if(!parents.contains(j) && j != root.value) {
                  a[root.value][j] = 1;
        }
     }
     parents.add(root.value);
     fill(a,n,root.left,parents);
     fill(a,n,root.right,parents);
     parents.remove(root.value);
}

Tuesday, 25 November 2014

A 2D array is such that each row in it is in ascending order and each column is in ascending order. How will you search for an element in this array?

Problem:

A 2D array is such that each row in it is in ascending order and each column is in ascending order. How will you search for an element in this array?

Solution:

The solution described below is O(n) solution.

Start from top right element,

  • If the element is equal to element we are searching for return the element.
  • If the element is greater than the element we are searching for, then all the element in the column below can be discard. Move to element left of current element. Repeat the steps with new current element.
  • If the element is less than the element we are searching for, then all the element in the row of current element can be discard. Move to element below of current element. Repeat the steps with new current element.
Pseudo code:

Pair find(int[][] a,int top, int bottom, int left, int right,int key) 
       if (top > bottom || left > right) return null;
       int current = a[top][right]
       if (current == key)
              return Pair(top,right)
       else if (current < key)
              return find(a,top+1,bottom,left,right,key)
       else
              return find(a,top,bottom,left,right-1,key)

 
Call find(0,n-1,0,m-1,key) to search for key.

A tree is represented in a matrix form such that A[i,j] = 1 if j is the ancestor of i. Otherwise A[i,j] = 0. Given this construct a normal binary search tree.

Problem:

A tree is represented in a matrix form such that A[i,j] = 1 if j is the ancestor of i. Otherwise A[i,j] = 0. Given this construct a normal binary search tree.

Solution:

Iterate over the array A and build array P, such that P[i] = # ancestor of node i. Thus, sum of A[i][j] for 0<=j<n

This will take O(n^2) time. While building the array P, keep track of node for which P[i] is 0. Certainly there can be only 1 such element i.e. root of the binary tree.

Now Node [0..i-1] will be in left sub tree of root and Node [i+1...n-1] will be right sub tree of root.

There can be only one node in 0..i-1 for which P[i] is 1, that will be root of left sub tree. Similar hold true for Nodes i+1...n-1. let index of node for which  P[j] is 1, 0<=j<=i-1, be k.

Node 0..k-1 will be in left sub tree of Node k which is left child of Node i. we need to find node x, 0<=x<=k-1 for which P[x] is 2. Hence we keep building our binary search tree.

Pseudo code

for i in 0..n-1
  p[i] = 0;
  for j in 0..n-1
     p[i] += a[i][j];
  return buildTree(p,0,n-1,0)

Node buildTree(int[] a,int left,int right,int rootIndex)
         for i in left...right
             if a[i] == rootIndex
                   Node root = new Node(i)
                   root.left = buildTree(a,left,i-1,rootIndex+1)
                   root.right = buildTree(a,i+1,right,rootIndex+1)
                   break;
          return root

The worst case complexity of this solution will be O(n^2) + O(n^2) which is O(n^2).
For average cases, where the binary tree is balanced complexity will be O(n^2) + O(n log n). This will be still be O(n^2) however second step will be faster in this case.

There are n petrol bunks arranged in circle. Each bunk is separated from the rest by a certain distance. You choose some mode of travel which needs 1litre of petrol to cover 1km distance.

Problem

There are n petrol bunks arranged in circle. Each bunk is separated from the rest by a certain distance. You choose some mode of travel which needs 1litre of petrol to cover 1km distance. You can’t infinitely draw any amount of petrol from each bunk as each bunk has some limited petrol only. But you know that the sum of litres of petrol in all the bunks is equal to the distance to be covered.
ie let P1, P2, … Pn be n bunks arranged circularly. d1 is distance between p1 and p2, d2 is distance between p2 and p3. dn is distance between pn and p1.Now find out the bunk from where the travel can be started such that your mode of travel never runs out of fuel.

Solution:

To understand the solution of problem first understand the below inequalities.
if a >= 0, a+b >=0, a+b+c>=0 and a+b+c+d < 0
Then following inequalities also hold true
b+c+d < 0, c+d<0 and d < 0

This would mean that when we start from any point (say P) and after moving through some tanks we run out of fuel at point (Say Q), then any points between P and Q cannot be starting point (including Q) so our next search has to start from Q+1. We will save this point as our starting point.
Note: We only need to consider till end point (assuming non-circular) because, the sum of all values would be zero, so we will be able to reach our current starting point from first point if we can reach end point from current starting point.

Now using array P[1..N]: Petrol capacity and D[1..N]: Distance between tanks
Compute array C[1..N] such that C[i] = P[i] - D[i], C[i] can be +ve, -ve or zero.

We start with C[1] and keep a variable sum to store sum of C[i]s so far. At any stage if C[k] makes are sum < 0, we start from k+1 and set sum = C[K+1]

Psuedo code:
index = 1;
sum = 0
result = index;
while(index <= N) {
     sum += C[index];
     if(sum < 0) {
         sum = 0;
         result = index + 1;
     }
     index++;
 }
 if(index >= N) {
     NO SOLUTION POSSIBLE;
 } else {
     result store our starting point
 }


         

Given an array of integers, find Pythagorean triplets. i.e. find a,b and c which satisfies a^2 + b^2 = c^2. Integers could be positive or negative.

Problem:
 Given an array of integers, find Pythagorean triplets. i.e. find a,b and c which satisfies a^2 + b^2 = c^2. Integers could be positive or negative.

Solution:
To solve this problem in naive approach, we can simply run O(n^3) solution by iterating over all triplets and then checking if Pythagorean property is indeed satisfied.

Can we optimize the solution? Answer is yes!! If we make use of sorting technique then we can make it O(n^2 * log(n)). 
If we square all the elements (all storing actual elements along side and storing all duplicates as well) and then sort the array of squares of the elements. Then for each pair (O(n^2)) we just need to find if sum of the square of these values exist in sorted array. Here come our life saving handy technique Binary Search into play which will can find if element exists in array in O(log n) so overall complexity becomes
 O(n^2 * log(n)).

Can we still do better???? Answer is again YES!! We can!!
We can maintain hash map for squares of elements therefore searching part of above can be done in O(1) making overall complexity O(n^2). But this would depend on choice of very good hash function and also may not be allowed in most of problems.

Then what next??? We will still use same sorting technique but with different flavor. We will sort the elements in such a way that a[i] will be before a[j] if a[i]*a[i] is less than a[j]*a[j].
Something similar to -1, 1, 2, 3 ,-5, 5 ....

Note that this array is actually sorted in terms of squares of values.
For each element of this array, we can find pair such that a[i]*a[i] + a[j]*a[j] = a[k]*a[k], where K is current element. 
Finding a pair can be done in O(n). This is similar to problem of finding X + Y = K in any sorted array in O(n).
Complexity:
Sorting step: O(nlogn)
Finding triplet : O(n^2)
Overall complexity O(n^2)

Working Code for O(n^2) solution

 import java.util.Arrays;  
 import java.util.Comparator;  
 import java.util.Scanner;  
 public class FindTriplet {  
      public static void main(String[] args) {  
           Scanner s = new Scanner(System.in);  
           int n = s.nextInt();  
           Integer[] a = new Integer[n];  
           for (int i = 0; i < n; i++) {  
                a[i] = s.nextInt();  
           }  
           Arrays.sort(a, new SquareSorter());  
           for (int i = 0; i < n; i++) {  
                for (int j = 0, k = n - 1; j < k;) {  
                     if (j == i) {  
                          j++;  
                     } else if (k == i) {  
                          k--;  
                     } else {  
                          int lhs = a[j] * a[j] + a[k] * a[k];  
                          int rhs = a[i] * a[i];  
                          if (lhs == rhs) {  
                               System.out.println("[" + a[j] + "(" + j + ")," + a[k]  
                                         + "(" + k + ")," + a[i] + "(" + i + ")," + "]");  
                               j++;  
                               k--;  
                          } else if (lhs > rhs){  
                               k--;  
                          } else {  
                               j++;  
                          }  
                     }  
                }  
           }  
      }  
 }  
 class SquareSorter implements Comparator<Integer> {  
      @Override  
      public int compare(Integer o1, Integer o2) {  
           return o1 * o1 - o2 * o2;  
      }  
 }  
Test case
Input:
8
-3 6 7 3 4 -5 4 5

Output:
[-3(0),4(3),-5(4),]
[3(1),4(2),-5(4),]
[-3(0),4(3),5(5),]
[3(1),4(2),5(5),]


Make array sorted with min cost.

Problem:
You are given an array of positive integers. Convert it to a sorted array with minimum cost (minimum number of operations). Only valid operation are
1) Decrement -> cost = 1
2) Delete an element completely from the array -> cost = value of element
For example: 4,3,5,6, -> cost 1 //cost is 1 to make 4->3
10,3,11,12 -> cost // cost 3 to remove 3
Solution:
The first solution that came to mind for this problem is greedy solution. In each step we assume that array elements to the left of current elements are already sorted and we are adding current element to. The cost of delete(not adding current element) would be value of element itself and the cost of decrements would be sum of cost of reducing all elements to the left of current element that are more than current element.
However, this above approach does not work in all cases. 
Consider 5 1 1 1 1 1 1 1 1 1, the above approach will remove all 1's and total cost will be 9 but the actual answer should be 4.
A DP solution is required to solve this problem.
Consider a function C, such that C(i,m) returns min cost required to make array A[0..i-1] sorted such that all elements in the array are less than m.
At any stage either the element should be deleted or decremented. For case where some elements need to be decremented.
m will be set of unique values in array A.
C(0,m) = max (a[0]-m,0), m unique values(A)
C(i,m) = Min (C(i-1,m) + a[i], a[i] <=m ? C(i-1,a[i]):C(i-1,m) + a[i] - m)
C(i-1,m) + a[i] is the scenario when current element is deleted, so the cost will be cost of making sorted array till i-1 with m as maximum value plus cost of deleting current element.
a[i] <=m ? C(i-1,a[i]):C(i-1,m) + a[i] - m is the scenario when current element is not deleted. If the current element is less than m then array elements to the left of it should not have any element more than a[i], so we find cost of making sorted array till i-1 with a[i] is maximum.
If the current element is more than m, then current element must be decremented. So the cost will be cost of making array till i-1 with m as maximum plus cost of reducing current element.
At the end we find Min(C(n-1,m)) for all m's.
Working Code


 import java.util.Comparator;  
 import java.util.Map;  
 import java.util.Scanner;  
 import java.util.TreeMap;  
 /**  
  * You are given an array of positive integers. Convert it to a sorted array  
  * with minimum cost (minimum number of operations). Only valid operation are <br>  
  * a. Decrement -> cost = 1 2)<br>  
  * b. Delete an element completely from the array -> cost = value of element For  
  * example: 4,3,5,6, -> cost 1 //cost is 1 to make 4->3 <br>  
  * 10,3,11,12 -> cost // cost 3 to remove 3  
  *   
  * Solution: The idea here is define a DP function c(i,m) such that it provides  
  * minimum cost required to make a[0..i] sorted such that no element is more  
  * than m. We start with c(0,m) and build our solution till c(n-1,m). The  
  * minimum value of c(n-1,m) is our solution.  
  *   
  * Here m is list of unique values in array A.  
  *   
  * @author sanahuja  
  *   
  */  
 public class GetMinCostToMakeArraySorted {  
      public static void main(String[] args) {  
           Scanner s = new Scanner(System.in);  
           int n = s.nextInt();  
           int[] a = new int[n];  
           Map<Integer, Integer> c = new TreeMap<Integer, Integer>(new IntMaxSorter());  
           for (int i = 0; i < n; i++) {  
                a[i] = s.nextInt();  
                if (!c.containsKey(a[i])) {  
                     c.put(a[i], 0);  
                }  
           }  
           // In first iteration, c(1,m) will be computed.  
           for (Integer m : c.keySet()) {  
                int cost = a[0] <= m ? 0 : a[0] - m;  
                c.put(m, cost);  
           }  
           for (int i = 1; i < n; i++) {  
                // Note value of M should be considered from high to low to avoid  
                // situation where c(i-1,a) (a<m) is actually returning c(i,m)  
                // because we are updating value iteratively. For this reason using tree map, but can be done more efficiently , tree map functionality may not be required.  
                for (Integer m : c.keySet()) {  
                     int costDelete = c.get(m) + a[i];  
                     int costDecrement = a[i] <= m ? c.get(a[i]) : c.get(m) + a[i]  
                               - m;  
                     int cost = costDecrement < costDelete ? costDecrement  
                               : costDelete;  
                     c.put(m, cost);  
                }  
           }  
           int minCost = Integer.MAX_VALUE;  
           for (Integer m : c.keySet()) {  
                if (c.get(m) < minCost) {  
                     minCost = c.get(m);  
                }  
           }  
           System.out.println(minCost);  
           s.close();  
      }  
 }  
 class IntMaxSorter implements Comparator<Integer> {  
      @Override  
      public int compare(Integer o1, Integer o2) {  
           return o2 - o1;  
      }  
 }  

Wednesday, 19 November 2014

Print Tree nodes at distance K from random node

Problem:
Given pointer to root of the binary tree and pointer to random node in the tree. Find all nodes that are at distance K from the random node.

Solution:

Algorithm:
a. If root is the random node then print all nodes from the root that are at distance K. Printing of nodes can be done recursively.
b. Search the random node in left sub tree of root. If node is found in left sub-tree and let say distance of random node from root is X. If X <= K, then print all nodes in the right sub-tree of the root that are are at distance K - X from the root.
c. If node is not found in the left sub-tree of the root then search the random node in right sub-tree of the root. Let us say that distance of random node in right sub-tree is X from the root. If X <= K, then print all nodes in the left sub-tree of the root that are are at distance K - X from the root.
d. Move one step closer toward the random node. i.e. if random node exist in left sub-tree of the root then set root = root.left, otherwise set root = root.right. Repeat step (a) to step (c).

This algorithm described above will be O(n^2) but if we use recursion carefully then we can make same solution O(n). In same recursion keep searching the node by moving towards the node and also printing the nodes in relevant sub-tree.

Working code for O(n) solution.
 public class PrintNodesAtK {  
      public static void main(String[] args) {  
           Tree root = new Tree(1);  
           Tree p1 = new Tree(2);  
           Tree p2 = new Tree(3);  
           Tree p3 = new Tree(4);  
           Tree p4 = new Tree(5);  
           Tree p5 = new Tree(6);  
           Tree p6 = new Tree(7);  
           Tree p7 = new Tree(8);  
           Tree p8 = new Tree(9);  
           Tree p9 = new Tree(10);  
           Tree p10 = new Tree(11);  
           Tree p11 = new Tree(12);  
           Tree p12 = new Tree(13);  
           root.left = p1;  
           root.right = p2;  
           p1.left = p3;  
           p1.right = p4;  
           p2.left = p5;  
           p2.right = p6;  
           p3.left = p7;  
           p4.left = p8;  
           p4.right = p9;  
           p6.left = p10;  
           p6.right = p11;  
           p10.right = p12;  
           searchNode(root, p6, 5);  
      }  
      public static int searchNode(Tree root, Tree random, int k) {  
           if (k == 0 || root == null) {  
                return -1;  
           } else if (random == root) {  
                printNodeAtK(root, k);  
                return 0;  
           } else {  
                int p = searchNode(root.left, random, k);  
                if (p != -1 && p + 1 <= k) {  
                     // Print root if d = 0  
                     int d = k - p - 1;  
                     if (d == 0) {  
                          System.out.println(root.value);  
                     } else {  
                          printNodeAtK(root.right, d - 1);  
                     }  
                } else if (p == -1) {  
                     p = searchNode(root.right, random, k);  
                     if (p != -1 && p + 1 <= k) {  
                          // Print root if d = 0  
                          int d = k - p - 1;  
                          if (d == 0) {  
                               System.out.println(root.value);  
                          } else {  
                               printNodeAtK(root.left, d - 1);  
                          }  
                     }  
                }  
                return p == -1 ? -1 : p + 1;  
           }  
      }  
      public static void printNodeAtK(Tree root, int k) {  
           if(root == null) {  
                return;  
           } else if (k == 0) {  
                System.out.println(root.value);  
           } else {  
                printNodeAtK(root.left, k - 1);  
                printNodeAtK(root.right, k - 1);  
           }  
      }  
 }  
 class Tree {  
      int value;  
      Tree left;  
      Tree right;  
      public Tree(int value) {  
           this.value = value;  
           left = null;  
           right = null;  
      }  
 }  

Monday, 17 November 2014

Display top 10 trending words

Problem:
There is a big file of words which is dynamically changing. We are continuously adding some words into it. How would you keep track of top 10 trending words at each moment?

Solution:
To solve this problem efficiently we need to look at two aspects:
a. We  must be able to detect if the word is a new word or it occurred previously. This can be done using data structure like Binary Search tree, Hash map, tries etc.
b. At any moment we must be able to retrieve top 10 words. This can be achieved using data structures like linked list, min heap or sorted array list.

The code mentioned below use hashmap and linked list. The linked list contain one node for every unique word and also maintain frequency of that word. The list is sorted at any given point of time, so first 10 nodes will be top 10 trending words.

To maintain mapping of nodes in the linked list and word, we use a hash map.

Adding new word : o(words)

 import java.util.HashMap;  
 import java.util.Scanner;  
 public class Top10Words {  
   public static void main(String[] args) {  
     Scanner s = new Scanner(System.in);  
           while(true) {  
                String word = s.next();  
                if(word.equals("-1")) {  
                     break;  
                } else if (word.equals("-2")) {  
                  printTopTen();  
                }else {  
                  addWord(word);  
                }  
           }  
           s.close();  
   }  
   public static HashMap<String,Node> nodeMap = new HashMap<String,Node>();  
   public static Node head = null;  
   public static Node tail = null;  
   public static void addWord(String word) {  
     if(nodeMap.containsKey(word)) {  
       Node p = nodeMap.get(word);  
       p.count++;  
       // move this node up the list if needed  
       while(p.prev != null && p.count > p.prev.count) {  
               Node t = p.prev;  
                  if(t.prev != null) {  
                   t.prev.next = p;  
                  }  
                  if(p.next != null) {  
                   p.next.prev = t;  
                  }  
                  t.next = p.next;  
                  p.prev = t.prev;  
                  p.next = t;  
                  t.prev = p;  
                  if(tail == p) {  
                   tail = t;  
                  }  
                  if(head == t) {  
                   head = p;  
                  }  
             }  
     } else {  
                // add new node to list and make entry in node map  
                Node newNode = new Node(word);  
                if(tail == null) {  
                     tail = newNode;  
                     head = newNode;  
                } else {  
                     tail.next = newNode;  
                     newNode.prev = tail;  
                     tail = newNode;  
       }  
       nodeMap.put(word,newNode);  
     }  
   }  
   public static void printTopTen() {  
     if(head == null) {  
         System.out.println("No Words till now.");  
        } else {  
          Node iter = head;  
             int i=0;  
             while(iter != null && i < 10) {  
              i++;  
                 System.out.println("Word: " + iter.word + " freq: " + iter.count);  
                 iter = iter.next;  
             }  
       }  
   }   
 }  
 class Node {  
   int count;  
   String word;  
   Node next;  
   Node prev;  
   public Node(String word) {  
    this.word = word;  
    this.count = 0;  
    this.next = null;  
    this.prev = null;  
   }   
 }  

As a improvement to above solution, we can modify the information that is stored in the hash map and linked list.

In the hashmap, store following information along with the word as key.
a. Frequency of the word
b. Reference to the node in the list. This will be null if the word is not currently stored in the list.

The linked list (doubly linked list) will have 10 nodes. Also maintain pointer to the head and tail of node.

Algorithm to add a new word:
a. If word does not exist in the hash map then add word to the hash map with frequency as 1. Also check if word should be added to the list (comparing with tail of the list). If word is added to the list, set node reference to the node in the list otherwise null.
b. If word exist in both hash map and list , increment the frequency by 1 in hash map and linked list.Update the linked list to maintain sorted order.
c. If word exist in hash map but not in linked list. Increment the frequency by 1 in hash map. Compare the tail value with new word frequency and check if word should be added to list by replacing the tail node. Readjust the linked list if required.
Note: When a node is deleted from linked list, set the node reference of corresponding hash map entry as null.

There are other possible solutions as well using other data structures. Trie can be used in place of hash map. Sometime it is not good practice to store lots of word in hash map. In such situations trie can be used.

In place of linked list we can also use min heap. It will reduce the complexity of adding new word from O(n) to O(log n). It will be more beneficial if we have to keep track of more words.

Solution using Trie and min Heap

Trie will be used to search for the word. It will also maintain frequency of the word.

Min Heap will be used to maintain top 10 words at any moment.

Algorithm:
  • Search the word in the Trie. If word exists, increment the frequency count.
    • Call min heapify function from index at which current word is stored in heap. If any node is pushed down/up the heap, keep updating reference index in the trie that indicate position of node in heap.
  • If Word does not exist, add the word and make frequency count 1
    • Compare the frequency of min element in heap with the new word. 
    • If the frequency is less than current word frequency or the size of the heap is less than maximum size of heap
      • Set the reference of min heap element to -1 indicate that it is no longer part of heap.
      • Add the node to the heap at index 1 and call min heapify function from index 1. If any node is pushed down the heap, keep updating reference index in the trie that indicate position of node in heap.

At any moment element in min heap represent top 10 trending words.


 import java.util.Scanner;  
 public class DisplayTop10TrendingWord {  
      public static void main(String[] args) {  
           Scanner s = new Scanner(System.in);  
           Heap heap = new Heap(4);  
           while (s.hasNext()) {  
                String word = s.next();  
                TrieNode node = Trie.getWordNode(word);  
                node.frequency++;  
                if (node.reference != -1) {  
                     heap.minHeapify(node.reference);  
                } else {  
                     heap.addNodeToHeap(node);  
                }  
                for (int i = 1; i <= heap.heapsize; i++) {  
                     System.out.print(heap.heap[i].word + "("  
                               + heap.heap[i].frequency + ") ");  
                }  
                System.out.println();  
           }  
           s.close();  
      }  
 }  
 class TrieNode {  
      int frequency;  
      TrieNode[] childs;  
      int reference;  
      String word;  
      public TrieNode() {  
           this.frequency = 0;  
           this.childs = new TrieNode[26];  
           this.reference = -1;  
           this.word = null;  
      }  
 }  
 class Trie {  
      private static final TrieNode root = new TrieNode();  
      public static TrieNode getWordNode(String word) {  
           TrieNode node = root;  
           for (int i = 0; i < word.length(); i++) {  
                char ch = word.charAt(i);  
                if (node.childs[ch - 'a'] == null) {  
                     TrieNode child = new TrieNode();  
                     node.childs[ch - 'a'] = child;  
                }  
                node = node.childs[ch - 'a'];  
           }  
           node.word = word;  
           return node;  
      }  
 }  
 class Heap {  
      TrieNode[] heap;  
      int maxSize;  
      int heapsize;  
      public Heap(int maxSize) {  
           this.maxSize = maxSize;  
           this.heapsize = 0;  
           heap = new TrieNode[maxSize + 1];  
      }  
      public static int parent(int index) {  
           return index / 2;  
      }  
      public static int left(int index) {  
           return index * 2;  
      }  
      public static int right(int index) {  
           return index * 2 + 1;  
      }  
      public void minHeapify(int index) {  
           int minIndex = index;  
           int left = left(index);  
           int right = right(index);  
           if (left <= heapsize && heap[left].frequency < heap[minIndex].frequency) {  
                minIndex = left;  
           }  
           if (right <= heapsize  
                     && heap[right].frequency < heap[minIndex].frequency) {  
                minIndex = right;  
           }  
           if (minIndex != index) {  
                TrieNode temp = heap[index];  
                heap[index] = heap[minIndex];  
                heap[index].reference = index;  
                heap[minIndex] = temp;  
                heap[minIndex].reference = minIndex;  
                minHeapify(minIndex);  
           }  
      }  
      public void addNodeToHeap(TrieNode node) {  
           if (heapsize >= maxSize && heap[1].frequency >= node.frequency) {  
                node.reference = -1;  
           } else if (heapsize < maxSize) {  
                heap[++heapsize] = node;  
                int index = heapsize;  
                node.reference = index;  
                while (index > 1  
                          && heap[parent(index)].frequency > heap[index].frequency) {  
                     TrieNode temp = heap[parent(index)];  
                     heap[parent(index)] = heap[index];  
                     heap[parent(index)].reference = parent(index);  
                     heap[index] = temp;  
                     heap[index].reference = index;  
                     index = parent(index);  
                }  
           } else {  
                int index = 1;  
                heap[index].reference = -1;  
                heap[index] = node;  
                node.reference = index;  
                minHeapify(index);  
           }  
      }  
 }  

Clone linked list with random pointers

Clone linked list where a node also has a random pointer apart from next pointer.

e.g.



The problem of cloning a linked list with only next pointer is fairly simple problem. But the trickier part here is to clone random pointer since while cloning the next pointers we don't have a way to determine the node that will be clone of the node random pointer points to.

So the basic ides to solve this problem is to clone the next pointers in the first pass while maintaining a mapping of actual node and cloned node.
In second pass, clone all the next pointers.

The mapping of actual node and cloned node can be achieved by following two ways depending upon problem constraints.
a. If use of extra memory other than memory for cloned nodes is allowed then simplest way is to use hash map to maintain mapping of actual nodes and cloned node. In first pass clone next pointers and keep storing each cloned node in the hash map. In second pass, clone the random pointers.

b. If use of extra memory is not allowed, then we can follow approach of adding cloned node between actual nodes. For example insert 5` (clone of node 5) between node 5 and node 4.

  • In first pass keep inserting cloned node between actual node. For above example linked list after first pass will look like:

          5--5'--4--4'--3--3'--2--2'--1--1'

  • In second pass clone the random pointers and jumping 2 steps in each iteration.

          For example random pointer of 5' should be next of random pointer of 5. Jump 2 steps to node 4 at the end of iteration

  • In third pass, restore all the pointers to split cloned and actual nodes.

Working code:

 import java.util.HashMap;  
 import java.util.Map;  
 /**  
  * Clone a linked list where each node has a next pointer and a random pointer  
  * to any node in the list.  
  *   
  * @author sanahuja  
  *   
  */  
 public class CloneList {  
      static Map<Node, Node> cloneNodes = new HashMap<Node, Node>();  
      public static void main(String[] args) {  
           Node head = new Node(5);  
           Node p1 = new Node(4);  
           Node p2 = new Node(3);  
           Node p3 = new Node(2);  
           Node p4 = new Node(1);  
           head.next = p1;  
           p1.next = p2;  
           p2.next = p3;  
           p3.next = p4;  
           head.random = p4;  
           p1.random = head;  
           p4.random = p3;  
           p2.random = p3;  
           printList(head);  
           Node newHead = cloneUsingHashMap(head);  
           printList(newHead);  
           Node newHead1 = cloneWithoutExtraMemory(head);  
           printList(newHead1);  
      }  
      private static void printList(Node head) {  
           Node t = head;  
           while (t != null) {  
                if (t.random != null) {  
                     System.out.print(t.value + "(" + t.random.value + ") -- ");  
                } else {  
                     System.out.print(t.value + " -- ");  
                }  
                t = t.next;  
           }  
           System.out.print("null");  
           System.out.println();  
      }  
      public static Node cloneNext(Node head) {  
           if (head == null) {  
                return null;  
           }  
           Node newHead = new Node(head.value);  
           cloneNodes.put(head, newHead);  
           // clone recursively  
           newHead.next = cloneNext(head.next);  
           return newHead;  
      }  
      public static Node cloneUsingHashMap(Node head) {  
           Node newHead = cloneNext(head);  
           Node t1 = head;  
           Node t2 = newHead;  
           while (t1 != null) {  
                t2.random = cloneNodes.get(t1.random);  
                t1 = t1.next;  
                t2 = t2.next;  
           }  
           return newHead;  
      }  
      // Without using hashmap or extra memory apart from node memories.  
      public static Node cloneWithoutExtraMemory(Node head) {  
           Node t1 = head;  
           while (t1 != null) {  
                Node newNode = new Node(t1.value);  
                newNode.next = t1.next;  
                t1.next = newNode;  
                t1 = t1.next.next;  
           }  
           // clone random pointers  
           t1 = head;  
           while (t1 != null) {  
                t1.next.random = t1.random;  
                t1 = t1.next.next;  
           }  
           // split clone nodes  
           Node newHead = head.next;  
           t1 = head;  
           Node t2 = head.next;  
           while (t2 != null) {  
                t1.next = t2.next;  
                t2.next = (t1.next == null) ? null : t1.next.next;  
                t1 = t1.next;  
                t2 = t2.next;  
           }  
           return newHead;  
      }  
 }  
 class Node {  
      int value;  
      Node next;  
      Node random;  
      public Node(int value) {  
           this.value = value;  
           this.next = null;  
           this.random = null;  
      }  
 }  

Serialize and deserialize N-ary tree (JAVA)

Write Java code to serialize and deserialize a N-ary tree

Encoding:

Data of each node will be represented using begin '.' and end '.'

')' will represent no more child for the node.

The basic idea is pack the tree using DFS, ')' will be written whenever current node's all child are written



The output will be :
.5..8..13..18..20..22.)))).17..23.))).9.).11..25..28..32.)).31..33.).34.).29.))).27.)))

Working code:



 import java.io.UnsupportedEncodingException;  
 import java.util.ArrayList;  
 import java.util.List;  
 import java.util.Stack;  
 public class SerializeNaryTree {  
      public static void main(String[] args) throws UnsupportedEncodingException {  
           Node root = new Node("5");  
           Node ch1 = new Node("8");  
           Node ch2 = new Node("9");  
           Node ch3 = new Node("11");  
           root.addChild(ch1);  
           root.addChild(ch2);  
           root.addChild(ch3);  
           Node ch4 = new Node("13");  
           Node ch5 = new Node("17");  
           Node ch6 = new Node("18");  
           Node ch7 = new Node("20");  
           Node ch8 = new Node("22");  
           ch1.addChild(ch4);  
           ch1.addChild(ch5);  
           ch4.addChild(ch6);  
           ch6.addChild(ch7);  
           ch7.addChild(ch8);  
           Node ch9 = new Node("23");  
           Node ch10 = new Node("25");  
           Node ch11 = new Node("27");  
           Node ch12 = new Node("28");  
           Node ch13 = new Node("32");  
           Node ch14 = new Node("31");  
           Node ch15 = new Node("33");  
           Node ch16 = new Node("34");  
           Node ch17 = new Node("29");  
           ch5.addChild(ch9);  
           ch3.addChild(ch10);  
           ch3.addChild(ch11);  
           ch10.addChild(ch12);  
           ch10.addChild(ch14);  
           ch12.addChild(ch13);  
           ch14.addChild(ch15);  
           ch14.addChild(ch16);  
           ch14.addChild(ch17);  
           String packed = Node.serialize(root);  
           System.out.println(packed);  
           Node compareTo = Node.deserialize(packed);  
           System.out.println(root.equals(compareTo));  
      }  
 }  
 class Node {  
      String key;  
      List<Node> childs = null;  
      public Node(String key) {  
           this.key = key;  
           this.childs = new ArrayList<Node>();  
      }  
      public void addChild(Node child) {  
           this.childs.add(child);  
      }  
      public static String serialize(Node root) {  
           StringBuilder result = new StringBuilder();  
           if (null != root) {  
                result.append(".");  
                result.append(root.key);  
                result.append(".");  
                for (Node child : root.childs) {  
                     result.append(Node.serialize(child));  
                }  
                result.append(")");  
           }  
           return result.toString();  
      }  
      public static Node deserialize(String node)  
                throws UnsupportedEncodingException {  
           Node result = null;  
           Stack<Node> stack = new Stack<Node>();  
           boolean isData = false;  
           StringBuilder data = null;  
           for (int i = 0; i < node.length(); i++) {  
                if (node.charAt(i) == '.') {  
                     isData = !isData;  
                     if (isData) {  
                          data = new StringBuilder();  
                     } else {  
                          Node child = new Node(data.toString());  
                          if (!stack.isEmpty()) {  
                               Node parent = stack.peek();  
                               parent.addChild(child);  
                          } else {  
                               result = child;  
                          }  
                          stack.push(child);  
                     }  
                } else {  
                     if (isData) {  
                          data.append(node.charAt(i));  
                     } else if (node.charAt(i) == ')') {  
                          stack.pop();  
                     } else {  
                          throw new UnsupportedEncodingException(  
                                    "Format not recognized.");  
                     }  
                }  
           }  
           return result;  
      }  
      public boolean equals(Node compareTo) {  
           if (null == compareTo) {  
                return false;  
           }  
           if (this.key.equals(compareTo.key)) {  
                boolean result = true;  
                for (int i = 0; i < this.childs.size(); i++) {  
                     result = result  
                               && this.childs.get(i).equals(compareTo.childs.get(i));  
                }  
                return result;  
           } else {  
                return false;  
           }  
      }  
 }  

Return the change

Given set of coins find the minimum number of coins required to return sum 'S'.
Let available set of coins be represented by array Coins. If sum can not be returned print -1
Assuming coins array is sorted.

Solution: O(N^2) where N is number of coins.

Sum[i] = min { Sum[i-Coin[j]] }  + 1, Sum[i-Coin[j]] != -1 && Coin[j] < i
if for all Sum[i-Coin[j]] == -1, Sum[i] = -1;

Test case

Coins: 1 3 4 5
Sum: 7
Min coin: 2

Sum:9
Min coin:2

Coins: 2 5 8 19
Sum:1
Min coin -1

Sum: 24
Min coin:2

Sum:23
Min coin: -1

Working code


 #include <stdio.h>  
  #include <iostream>  
  #define max(a,b) a>b?a:b  
  using namespace std;  
  int main() {  
  int n;  
  cin>>n;  
  int coin[n];  
  for(int i=0;i<n;i++) {  
  cin>>coin[i];  
  }  
  int s;  
  cin>>s;  
  int found = 0,min;  
  int sum[s+1];  
  sum[0] = 0;  
  for(int i=1;i<=s;i++) {  
  found = 0;  
  min = i;  
  for(int j=0;j<n && coin[j] <= i;j++) {  
   if(sum[i-coin[j]] != -1) {  
   found = 1;  
   if(sum[i-coin[j]] < min) {  
   min = sum[i-coin[j]];  
   }  
   }  
  }  
  if(!found) {  
   sum[i] = -1;  
  } else {  
   sum[i] = min + 1;  
  }  
  }  
  cout<<sum[s]<<endl;  
  return 0;  
  }  

Finding character with most occurrence in a continuous stream.

Problem: Given a continuous character stream, at any stage find and remove (set its occurance count to 0) the character that has occured highest number of time.

Solution: The problem can be solved efficient using combination of hash map and linked list (or max heap). The below code is using hash map and linked list.

The information that should stored in hash map is reference to the node (linked list or max heap). The key in the hash map is the character. If problem is limited to the smaller set of alphabet then array can also be used in place of hash map.

Whenever a character is read from the stream, then reference (linked list or max heap) is retrieved from the hash map. If reference does not exist then a new node will be created and inserted in the linked list or hash map. Otherwise, frequency of character is updated in the node retrieved using reference from hash map.

After the frequency of node is updated, linked list must be worked upon to ensure sorted order is maintained ( O(n) operation). If max heap is used then maxHeapify operation must be run to ensure heap property is maintained.

For retrieving most occurred character return and remove head of linked list or root of the max heap.

 import java.io.BufferedInputStream;  
 import java.io.IOException;  
 import java.io.InputStream;  
 import java.util.HashMap;  
 import java.util.Map;  
 /**  
  * Given a continuous character stream, at any stage find and remove (set its  
  * occurance count to 0) the character that has occured highest number of time.  
  *   
  * @author sanahuja  
  *   
  */  
 public class DoublyList {  
      private static Node head = null;  
      private static Node tail = null;  
      private static Map<Character, Node> chars = new HashMap<Character, Node>();  
      public static void main(String[] args) throws IOException {  
           InputStream s = new BufferedInputStream(System.in);  
           while (true) {  
                char c = (char) s.read();  
                if (c == '\r' || c == '\t' || c == ' ' || c == '\n') {  
                     continue;  
                } else if (c == '-') {  
                     if (head == null) {  
                          System.out.println("No char yet.");  
                     } else {  
                          // find and remove highest frequency char  
                          System.out.println("Highest char " + head.c  
                                    + " with count " + head.frequency);  
                          chars.remove(head.c);  
                          if (head == tail) {  
                               head = null;  
                               tail = null;  
                          } else {  
                               Node t = head;  
                               head = t.next;  
                               t.next = null;  
                               head.prev = null;  
                          }  
                     }  
                } else if (c == '$') {  
                     break;  
                } else {  
                     // add the char to list  
                     if (chars.containsKey(c)) {  
                          // update existing  
                          Node n = chars.get(c);  
                          n.frequency++;  
                          while (n.prev != null && n.frequency > n.prev.frequency) {  
                               Node p = n.prev;  
                               if (p.prev != null) {  
                                    p.prev.next = n;  
                               }  
                               p.next = n.next;  
                               if (n.next != null) {  
                                    n.next.prev = p;  
                               }  
                               n.prev = p.prev;  
                               p.prev = n;  
                               n.next = p;  
                               if (tail == n) {  
                                    tail = p;  
                               }  
                          }  
                          if (n.prev == null) {  
                               head = n;  
                          }  
                     } else {  
                          // add new node  
                          Node n = new Node(c);  
                          if (tail == null) {  
                               tail = n;  
                          } else {  
                               tail.next = n;  
                               n.prev = tail;  
                               tail = n;  
                          }  
                          if (head == null)  
                               head = n;  
                          chars.put(c, n);  
                     }  
                }  
           }  
           s.close();  
      }  
 }  
 class Node {  
      public char c;  
      public int frequency;  
      Node next;  
      Node prev;  
      public Node(char c) {  
           this.c = c;  
           this.frequency = 1;  
           next = null;  
           prev = null;  
      }  
 }