Saturday, March 30, 2013

Palindrome Partitioning

Given a string, a partitioning of the string is a palindrome partitioning if every substring of the partition is a palindrome. For example, “aba|b|bbabb|a|b|aba” is a palindrome partitioning of “ababbbabbababa”. Determine the fewest cuts needed for palindrome partitioning of a given string. For example, minimum 3 cuts are needed for “ababbbabbababa”. The three cuts are “a|babbbab|b|ababa”. If a string is palindrome, then minimum 0 cuts are needed. If a string of length n containing all different characters, then minimum n-1 cuts are needed.

Solution
If the string is palindrome, then we simply return 0. Else, like the Matrix Chain Multiplication problem, we try making cuts at all possible places, recursively calculate the cost for each cut and return the minimum value.

Let the given string be str and minPalPartion() be the function that returns the fewest cuts needed for palindrome partitioning. following is the optimal substructure property.

// i is the starting index and j is the ending index. i must be passed as 0 and j as n-1
minPalPartion(str, i, j) = 0 if i == j. // When string is of length 1.
minPalPartion(str, i, j) = 0 if str[i..j] is palindrome.

// If none of the above conditions is true, then minPalPartion(str, i, j) can be
// calculated recursively using the following formula.
minPalPartion(str, i, j) = Min { minPalPartion(str, i, k) + 1 +
minPalPartion(str, k+1, j) }
where k varies from i to j-1



Following is Dynamic Programming solution. It stores the solutions to subproblems in two arrays P[][] and C[][], and reuses the calculated values.

public class PalindromPartitioning {

// Returns the minimum number of cuts needed to partition a string
// such that every part is a palindrome
public static int minPalPartion(String str) {
// Get the length of the string
int n = str.length();

/*
* Create two arrays to build the solution in bottom up manner C[i][j] =
* Minimum number of cuts needed for palindrome partitioning of
* substring str[i..j] P[i][j] = true if substring str[i..j] is
* palindrome, else false Note that C[i][j] is 0 if P[i][j] is true
*/
int C[][] = new int[n][n];
boolean P[][] = new boolean[n][n];

int i, j, k, L; // different looping variables

// Every substring of length 1 is a palindrome
for (i = 0; i < n; i++) {
P[i][i] = true;
C[i][i] = 0;
}

/*
* L is substring length. Build the solution in bottom up manner by
* considering all substrings of length starting from 2 to n.
*/
for (L = 2; L <= n; L++) {
// For substring of length L, set different possible starting
// indexes
for (i = 0; i < n - L + 1; i++) {
j = i + L - 1; // Set ending index

// If L is 2, then we just need to compare two characters. Else
// need to check two corner characters and value of P[i+1][j-1]
if (L == 2)
P[i][j] = (str.charAt(i) == str.charAt(j));
else
P[i][j] = (str.charAt(i) == str.charAt(j))
&& P[i + 1][j - 1];

// IF str[i..j] is palindrome, then C[i][j] is 0
if (P[i][j] == true)
C[i][j] = 0;
else {
// Make a cut at every possible location starting from i to
// j,and get the minimum cost cut.
C[i][j] = Integer.MAX_VALUE;
for (k = i; k <= j - 1; k++)
C[i][j] = Math.min(C[i][j], C[i][k] + C[k + 1][j] + 1);
}
}
}

// Return the min cut value for complete string. i.e., str[0..n-1]
return C[0][n - 1];
}

public static void main(String[] args) {
String str = "ababbbabbababa";
System.out.println("Min cuts needed for Palindrome Partitioning is "
+ minPalPartion(str));
}

}

Friday, March 29, 2013

Partition Problem

Partition problem is to determine whether a given set can be partitioned into two subsets such that the sum of elements in both subsets is same.

Examples arr[] = {1, 5, 11, 5}
Output: true
The array can be partitioned as {1, 5, 5} and {11}

arr[] = {1, 5, 3}
Output: false
The array cannot be partitioned into equal sum sets.
Following are the two main steps to solve this problem:
1) Calculate sum of the array. If sum is odd, there can not be two subsets with equal sum, so return false.
2) If sum of array elements is even, calculate sum/2 and find a subset of array with sum equal to sum/2.
Dynamic Programming Solution
The problem can be solved using dynamic programming when the sum of the elements is not too big.
We can create a 2D array part[][] of size (sum/2)*(n+1). And we can construct the solution in bottom up manner such that every filled entry has following property part[i][j] = true if a subset of {arr[0], arr[1], ..arr[j-1]} has sum
             equal to i, otherwise false
public class PartitionSubsetSum {

public static boolean findPartion(int arr[]) {
int sum = 0;
int i, j;
// Calculate sum of all elements
for (i = 0; i < arr.length; i++)
sum += arr[i];
if (sum % 2 != 0)
return false;
boolean part[][] = new boolean[sum / 2 + 1][arr.length + 1];
// initialize top row as true
for (i = 0; i <= arr.length; i++)
part[0][i] = true;
// initialize leftmost column, except part[0][0], as 0
for (i = 1; i <= sum / 2; i++)
part[i][0] = false;
// Fill the partition table in bottom up manner
for (i = 1; i <= sum / 2; i++) {
for (j = 1; j <= arr.length; j++) {
part[i][j] = part[i][j - 1];
if (i >= arr[j - 1])
part[i][j] = part[i][j] || part[i - arr[j - 1]][j - 1];
}
}
return part[sum / 2][arr.length];
}
public static void main(String[] args) {
int arr[] = { 3, 1, 1, 2, 2, 1 };
if (findPartion(arr) == true)
{
System.out.println("Can be divided into two subsets of equal sum");
}
else
{
System.out.println("Can not be divided into two subsets of equal sum");
}
}
}

Next greater element

Problem:

Given an array, print the next greater element for every element. Elements for which no greater element exist, print next greater element as -1.

For the elements of the array [4, 5, 2, 25, 20, 11, 13, 21, 3] greater elements are as follows.

4 --> 5
5 --> 25
2 --> 25
25 --> -1
20 --> 21
11 --> 13
13 --> 21
21 --> -1
3 --> –1

Solution : O(n)

1. Take stack A.
2. Initially the stack is empty. Traverse the array from left to right. Do for every element
a. if the stack is empty push the element in the stack
b. if the stack is non empty keep on popping elements from the stack till element popped < current element. The next greater element for every popped element would be the current element. If element popped > current element. Push popped element and then current element on the stack.
3. When the traversal is complete, if the stack is nonempty pop elements from the stack and set the values of next greater element for these popped element as -1.

eg. for array [2, 25, 20, 11, 21, 3]
stack A -> emtpy
1. push element 2 on stack A->2
2. pop 2 from the stack. Compare it with 25 since 2 < 25 set next greater element of 2 as 25.
A->25
3. pop 25 from the stack. 25 > 20 . Push 25 on the stack. Push 20 on the stack.
A->25->20
4. pop 20 from the stack. 20>11. Push 20 on the stack. Push 11 on the stack.
A->25->20->11
5. pop 11 from the stack. 11 < 21. Set next greater element of 11 as 21. Pop 20 from the stack. 20 < 21. Set next greater element of 20 as 21. Pop 25 from the stack. 25 > 21. Push 25 on stack. Push 21 on stack.
A->25->21
6. pop 21 from the stack. 21 > 3. Push 21 on stack. Push 3 on stack.
A->25->21->3
Set the value of next greater elements for all the elements present in the stack as -1.

import java.util.Stack;

public class NextGreaterElement {

public static void NGE(int a[]) {
Stack<Integer> stack = new Stack<Integer>();
int current;
int next;
stack.push(a[0]);
for (int i = 1; i < a.length; i++) {
next = a[i];
if (!(stack.isEmpty())) {
current = stack.peek();
while (current < next) {
if (stack.isEmpty()) {
break;
}
current = stack.pop();
System.out.println(current + "," + next);
}
stack.push(next);
}
}

while(!(stack.isEmpty()))
{
current = stack.pop();
System.out.println(current + ", -1");
}
}

public static void main(String[] args) {
int a[] = { 11, 3, 21, 3, 25, 6, 2 };
NGE(a);
}
}

Rain Water Trap

Given a non-negative integer array representing an elevation map where the width of each bar is 1, compute how much water it can trap after raining. For example, given [0,1,0,2,1,0,1,3,2,1,2,1], returns 6.

Follow up:
What is the complexity of your solution?

rainwatertrap

for input:
A=[0,1,0,2,1,0,1,3,2,1,2,1]
N= sizeof(A)

compute Left[] where Left[i]= Max(A[0..i])     Calculate Max bar height from node 0-i
Left=[0,1,1,2,2,2,2,3,3,3,3,3]

compute Right[] where Right[i]= Max(A[i..N])    Calculate Max bar height from node i-n
Right=[3,3,3,3,3,3,3,3,2,2,2,1]

compute D[] where D[i]=Min(Left[i],Right[i])    Calculate Min bar height between bar before Vs after i, coz only this much water could fill
D=[0,1,1,2,2,2,2,3,2,2,2,1]

compute E[] where E[i]=D[i]-A[i]            Subtract the height of bar i from Max water bars could hold before Vs after
E[i]=[0,0,1,0,1,2,1,0,0,1,0,0]

the answer is sum(E[i])
the complexity is O(N)

public class Solution {
public int trap(int[] A) {
// Start typing your Java solution below
// DO NOT write main() function
int[]left=new int[A.length];
int[]right=new int[A.length];
if(A.length==0) return 0;
int max=0;
for(int i =0;i<A.length;i++){
max=Math.max(max,A[i]);
left[i]=max;
}
max=0;
for(int i =A.length-1;i>=0;i--){
max=Math.max(max,A[i]);
right[i]=max;
}
max=0;
for(int i =0;i<A.length;i++)
max+=Math.min(left[i],right[i])-A[i];
return max;
}
}

maximum value of no contiguous subsequence

maximum value of no contiguous subsequence
Given a sequence of n numbers A(1) ... A(n), give an algorithm for finding a contiguous subsequence A(i) ... A(j) for which the sum of elements in the subsequence is maximum. Here the condition is we should not select two contiguous numbers.
follow up:
what if we should not select three contiguous numbers

 

//max subarray with no 2 contiguous 
public static int maxSubWithNo2Con(int[]A){
int dp[] = new int[A.length];
dp[0]=A[0];
dp[1]=Math.max(A[0],A[1]);
for(int i =2; i < A.length;i++){
dp[i] = Math.max(A[i] + dp[i-2], dp[i-1]);
}
return dp[A.length-1];
}
//no three contiguous
public static int maxSubWithNo3Con(int[]A){
int dp[] = new int[A.length];
dp[0]=A[0];
dp[1]=Math.max(A[0]+A[1],Math.max(A[0],A[1]));
dp[2]=Math.max(A[2]+A[0], A[1]+A[0]);
for(int i = 3;i<A.length;i++){
dp[i]=Math.max(dp[i-2]+A[i], Math.max(A[i]+A[i-1]+dp[i-3],dp[i-1]));
}
return dp[dp.length-1];

}
public static void main(String[] args){
int ar[] ={1,-1,2,3,-1,-2,0,2,4,5,-2,-2,5};
System.out.println(maxSubWithNo2Con(ar));
System.out.println(maxSubWithNo3Con(ar));
}

Bad neighbours

Question: find the max subsequence sum but the elements can not be close to each other, the first and the end are not allowed either.
Solution: This is another classic example of using dynamic programming.

public class BadNeighbors {
public int maxDonations(int[] donations) {
List<Integer> l1 = new ArrayList<Integer>();
List<Integer> l2 = new ArrayList<Integer>();
int n = donations.length;
for (int i = 0; i < n; i++) {
if (i == 0) {
l1.add(donations[i]);
} else if (i== n-1) {
l2.add(donations[i]);
} else {
l1.add(donations[i]);
l2.add(donations[i]);
}
}
return Math.max(findMax(l1), findMax(l2));
}

private int findMax(List<Integer> l1) {
if (l1.size() == 1)
return l1.get(0);
if (l1.size() == 2)
return Math.max(l1.get(0), l1.get(1));
if (l1.size() == 3)
return Math.max(l1.get(0) + l1.get(2), l1.get(1));
int[] dp = new int[l1.size()];
dp[0] = l1.get(0);
dp[1] = Math.max(l1.get(0), l1.get(1));
dp[2] = Math.max(l1.get(0) + l1.get(2), l1.get(1));
int i;
for (i=3; i<l1.size(); i++) {
dp[i] = Math.max(l1.get(i)+dp[i-2], l1.get(i-1)+dp[i-3]);
}
return dp[l1.size()-1];
}

}

word segment from a string.

Given an input string and a dictionary of words, implement a method that breaks up the input string into a space-separated string of dictionary words that a search engine might use for "Did you mean?" For example, an input of "applepie" should yield an output of "apple pie".

A back tracking solution would produce O(2^n) complexity. An efficient solution using memorization or dynamic programming could bring this problem down to O(n^2).

import java.util.HashMap;
import java.util.Map;
import java.util.Set;

public class WordSegment {

Map<String, String> memoized = new HashMap<String, String>();

public String SegmentString(String input, Set<String> dict) {
if (dict.contains(input))
return input;
if (memoized.containsKey(input)) {
return memoized.get(input);
}
int len = input.length();
for (int i = 1; i < len; i++) {
String prefix = input.substring(0, i);
if (dict.contains(prefix)) {
String suffix = input.substring(i, len);
String segSuffix = SegmentString(suffix, dict);
if (segSuffix != null) {
memoized.put(input, prefix + " " + segSuffix);
return prefix + " " + segSuffix;

}
}

}
memoized.put(input, null);
return null;
}
}

Distance between 2 cities

There is a straight road with several towns along the road. Your program is given the distance between each pair of adjacent towns. You need to write a class to accept this input (as initialization) and has a method to calculate the distances between two arbitrary towns.

class Road - initialized with list of towns and distances between adjacent towns
    Road(String[] towns, int[] distances)
    Road.findDistance(String from, String to)
    Road.findDistance - takes two towns and returns distance between them

A --- B ---- C --- D --- E
    10    23     12     10

towns = {“A”, “B”, “C”, “D”, “E”}
distances = {10, 23, 12, 10}

findDistance(“C”, “E”) = 22 -> takes constant time.

import java.util.HashMap;
import java.util.Map;

public class Road {

static Map<String, Integer> map = new HashMap<String, Integer>();
int size;
static int distance_sum[];

public Road(String[] towns, int[] distances) {

if (towns.length < 2 || distances.length < 1
|| distances.length != towns.length - 1)
return;

distance_sum = new int[distances.length];
for (int i = 0; i < towns.length; i++) {
map.put(towns[i], i);
}

distance_sum[0] = 0;
for (int i = 1; i < distances.length + 1; i++) {
distance_sum[i] += distances[i - 1] + distance_sum[i - 1];
}
}

public static int findDistance(String from, String to) {
int startIndex = -1;
if (map.get(from) != null)
startIndex = map.get(from);

int toIndex = -1;
if (map.get(to) != null)
toIndex = map.get(to);

if (toIndex == -1 || startIndex == -1)
return -1;
if (startIndex == toIndex)
return 0;

if (startIndex > toIndex) {
return distance_sum[startIndex] - distance_sum[toIndex];
} else
return distance_sum[toIndex] - distance_sum[startIndex];
}

}

a to the power b using log n

Generate A to power B

int power(int a, int b) {
if (b == 0)
return 1;
if (b == 1)
return a;
if (b<0)
return 1/power(a, -b); // a should not be 0
int x = power(a, b/2);
return b&1? x*x*a:x*x;
}

range sum query

Given an array arr[0 . . . n-1]. We should be able to
1 Find the sum of elements from index l to r where 0 <= l <= r <= n-1
2 Change value of a specific element of the array arr[i] = x where 0 <= i <= n-1.

A simple solution is to run a loop from l to r and calculate sum of elements in given range. To update a value, simply do arr[i] = x. The first operation takes O(n) time and second operation takes O(1) time.

Another solution is to create another array and store sum from start to i at the ith index in this array. Sum of a given range can now be calculated in O(1) time, but update operation takes O(n) time now. This works well if the number of query operations are large and very few updates.

Another approach is <O(N), O(sqrt(N))> solution
An interesting idea is to split the vector in sqrt(N) pieces. We will keep in a vector M[0, sqrt(N)-1] the sum of the values of each section.

Group the input by chunks of O(n^1/2), and store the sum of each (chunk 0: sum of arr[0] through arr[sqrt(n)-1]; chunk 1: sum of arr[sqrt(n)] through arr[2*sqrt(n)-1]; etc.). That's your preprocessing step.
Now, each query is the sum of some number (maybe 0) of complete chunks of size O(n^1/2) plus possibly parts of the two chunks on each end of the range. There are at most O(n^1/2) complete chunks to sum that are part of the range. Now consider the two chunks that are partially covered by the range. Each of these 2 chunks has at most O(n^1/2) numbers, so we can just add the individual numbers to the total and still keep the time within O(n^1/2).

Another approach is using segment trees

We can use a Segment Tree to do both operations in O(Logn) time.

Representation of Segment trees
1. Leaf Nodes are the elements of the input array.
2. Each internal node represents some merging of the leaf nodes. The merging may be different for different problems. For this problem, merging is sum of leaves under a node.

An array representation of tree is used to represent Segment Trees. For each node at index i, the left child is at index 2*i+1, right child at 2*i+2 and the parent is at (i-1)/2.

Query for Sum of given range
Once the tree is constructed, how to get the sum using the constructed segment tree. Following is algorithm to get the sum of elements.

int getSum(node, l, r) 
{
if range of node is within l and r
return value in node
else if range of node is completely outside l and r
return 0
else
return getSum(node's left child, l, r) +
getSum(node's right child, l, r)
}


Update a value


Like tree construction and query operations, update can also be done recursively. We are given an index which needs to updated. Let diff be the value to be added. We start from root of the segment tree, and add diff to all nodes which have given index in their range. If a node doesn’t have given index in its range, we don’t make any changes to that node.



References :



http://community.topcoder.com/tc?module=Static&d1=tutorials&d2=lowestCommonAncestor



http://www.geeksforgeeks.org/segment-tree-set-1-sum-of-given-range/



http://www.cse.iitk.ac.in/users/aca/lop12/slides/06.pdf

Sunday, March 24, 2013

Find top k from given array

You are given an array A of k values which contain int values in sorted (asec) order. Find top k values (asec) which can either be the number from the array A, or sum of any two numbers from A or sum of any three numbers from A. So, if A's values are represented as : a1,a2,...,ak , the possible numbers can be: a(i), a(i)+a(j), a(i)+a(j)+a(l) for any i,j,l < k

Ex: A[7] = {3,4,5,15,19,20,25}
output B[7] = {3,4,5,(3+4),(3+5),(4+5),(3+4+5)}
create a min-heap out of array A,
now get the root, ie 3, and do min-heapify.
after that again get the root ie 4, add it to the rest of the elements seen so far and push back on min-heap.
so in output we have 3, 4
heap we have 5, 7, 15, 19, 20, 25
get the root, add it to each element of the outpu array and push the result back on heap.
also take 2 elements at a time from the array and add it to 5 and push back the result on min-heap and heapify.
output we have now, 3, 4, 5
pushing on heap - (3+5), (4+5) (3+4+5)
heap is now: 7, 8, 9, 12, 15, 19, 20, 25
again get the root and do the above steps,
finally we will have the output array as:
3, 4, 5, 7, 8, 9, 12


Total time complexity: 
klogk + k^2

Saturday, March 23, 2013

Partition an array into 2 parts with equal average

we have to find partition such that average of two partitions are same, it seems that we need to solve the problem of finding all possible sum for a subset of size k (for 1<=k<=n/2), where n is total # of items.
Let S1 = sum of partition 1
n1 = # of items in partition 1
S2 = sum of partition 2
n2 = # of items in partition 2
S = S1+S2
n = n1+n2
Since, S1/n1 = S2/n2, it implies S1/n1 = S2/n2 = (S1+S2)/(n1+n2) = S/n
Now, we populate a table of size (N/2) x N x S, where each entry T[k][i][j] is 1 if we there exists some subset of size k using the set of elements {1,2,...,i} that sum to j. During the computation of this table entries, if we ever found that j/k = S/n, there exists a way to make a partition with equal average. T[k][i][j] can be generated as a recurrence like :

T[k][i][j] = T[k-1][n-1][j-item_i] || T[k][i-1][j]


An example to follow above idea: items = {2, 4, 4, 6, 6, 8}
N = 6, S = 30, Avg = 5
for k = 2, we can generate T[2][4][10] = 1
which implies Avg. of this partition = 10/2 = 5


TC would be O(N^2*S), space could be reduced to O(N*S).



public class Partition {

public static void main(String[] args) {
int [] A = {2, 4, 4, 6, 6, 8};
partitionEqualAvg(A);
}

public static void partitionEqualAvg(int [] A) {
int n = A.length;
int S = sumOfArray(A);
double avg = S/n;
int subsetLen = n/2;

boolean [][][] T = new boolean[subsetLen+1][n+1][S+1];

for (int i=0; i<=n; i++) {
T[0][i][0] = true;
}

for (int k=1; k<=subsetLen; k++) {
for (int i=1; i<n; i++) {
for (int j=1; j<=S; j++) {
if (A[i] <= j) {
T[k][i][j] = T[k-1][i-1][j-A[i]];
}
T[k][i][j] = T[k][i][j] || T[k][i-1][j];
if (T[k][i][j]) {
double tempAvg = (double)j/(double)k;
if (Math.abs((tempAvg - avg)) <= 0.0001 ) {
System.out.println("Partition 1: sum " + j + " of " + k +" items");
System.out.println("Partition 2: sum " + (S-j) + " of" + (n-k)+" items");
return ;
}
}
}
}
}
System.out.println("No partition with equal average possible!");
}

public static int sumOfArray(int [] A) {
int len = A.length;
int sum = 0;
for (int i=0; i<len; i++) {
sum += A[i];
}
return sum;
}
}

Kth Smallest Element in a binary search tree

  1. k == num_elements(left subtree of T) +1, then the answer we're looking for is the value in node T
  2. k > num_elements(left subtree of T) then obviously we can ignore the left subtree, because those elements will also be smaller than the kth smallest. So, we reduce the problem to finding the k - num_elements(left subtree of T) smallest element of the right subtree.
  3. k < num_elements(left subtree of T), then the kth smallest is somewhere in the left subtree, so we reduce the problem to finding the kth smallest element in the left subtree.
public class KthSmallestElement {
private static Node root;

public static void main(String[] args) {
int[] A = { 8, 3, 10, 1, 6, 14, 4, 7, 13 };
root = buildBST(root, A);
System.out.println("inorder: ");
printBSTInorder(root);
System.out.println();
int sizeBST = sizeOfBST(root);
System.out.println("Size of BST: " + sizeBST);

for (int i = 1; i <= sizeBST; i++) {
Node node = kthSmallestNode(root, i);
System.out.println(i + " largest node: " + node.data);
}
}

public static Node kthSmallestNode(Node node, int k) {
if (null == node) {
return null;
}
int r = sizeOfBST(node.left) + 1;
if (k == r) {
return node;
}
if (k < r) {
return kthSmallestNode(node.left, k);
} else {
return kthSmallestNode(node.right, k - r);
}
}

public static int sizeOfBST(Node node) {
if (null == node) {
return 0;
}
return (sizeOfBST(node.left) + 1 + sizeOfBST(node.right));
}

public static Node buildBST(Node node, int[] A) {
if (A == null) {
return null;
}
int len = A.length;
for (int i = 0; i < len; i++) {
node = insertIntoBST(node, A[i]);
}
return node;
}

private static Node insertIntoBST(Node node, int value) {
if (null == node) {
return new Node(value);
}
if (value <= node.data) {
node.left = insertIntoBST(node.left, value);
} else {
node.right = insertIntoBST(node.right, value);
}
return node;
}

public static void printBSTInorder(Node node) {
if (null == node) {
return;
}
if (null != node.left) {
printBSTInorder(node.left);
}
System.out.print(node.data + " ");
if (null != node.right) {
printBSTInorder(node.right);
}
}
}

class Node {
Integer data;
Node left;
Node right;

public Node(Integer data) {
this.data = data;
this.left = null;
this.right = null;
}
}

Thursday, March 21, 2013

Longest Arithmetic Progression

Given an array of integers A, give an algorithm to find the longest Arithmetic progression in it, i.e find a sequence i1 < i2 < … < ik, such that  A[i1], A[i2], …, A[ik] forms an arithmetic progression, and k is the largest possible. The sequence S1, S2, …, Sk is called an arithmetic progression if Sj+1 – Sj is a constant

solution:
The key is use dynamic programming. We can use the following property here :
If ..., a_{i+1}, a_i, ..., a_3, a_2, a_1, b, c_1, c_2, ..., c_i, c_{i+1}, ... is an A.P., then
a_i + c_i = 2b

Think about how to find a number which is the average of other two numbers in a sorted array
Says pDP[i][j] is the arithmetic progression starting at i and j
for every a, b, c, where b is the average of a and c.
pDP[a][b] = 1 + pDP[b][c]

Algo would be something like :
S = sort(A) .. where A is the given array
Consider each element in S as 'b' (as defined above) and move outward (on both sides) and keep finding all the A.P elements with b as center.
One should be able to create a list 3-tuples and their A.P constants. Then, simply grouping by A.P constants and chaining these 3-tuples in each group should give the chain as well as their lengths. Simply get the one with max length from then on. Time complexity would be O(n^2).

import java.util.Arrays;
import java.util.Comparator;

public class ArthimeticProgression {

public static void main(String[] args) {
int a[] = {1,-2,3,5,7,-3,8,11,15,19,-5,22,25,-11};
PrintLongestProg(a);
}

public static int FindIndex(RECORD rc[], int n, int index)
{
for (int i = 0; i < n; i++)
{
if (rc[i].nIndex == index)
return i;
}
return -1;
}

public static int PrintLongestProg(int a[])
{
int n = a.length;
if (n <= 1) return n;

RECORD recs[] = new RECORD[n];
for (int i = 0; i < n; i++)
{
recs[i] = new RECORD();
recs[i].nVal = a[i];
recs[i].nIndex = i;
}

Arrays.sort(recs, new LessThan());

int pDP[][] = new int[n][n];

for (int i = 0; i < n; i++)
for (int j = 0; j < n; j++)
pDP[i][j] = 2;

int nStart = n - 2;
int nEnd = n - 1;

for (int i = n - 2; i >= 1; i--)
{
int index = FindIndex(recs, n, i);
if (index < 0) break;

int l = index - 1;
int r = index + 1;
while (l >= 0 && r < n)
{
if (recs[l].nVal + recs[r].nVal == 2 * recs[index].nVal)
{
if (recs[l].nIndex < i && recs[r].nIndex > i)
{
pDP[recs[l].nIndex][i] = pDP[i][recs[r].nIndex] + 1;
if (pDP[nStart][nEnd] < pDP[recs[l].nIndex][i])
{
nStart = recs[l].nIndex;
nEnd = i;
}
}

l--;
r++;
}
else if (recs[l].nVal + recs[r].nVal < 2 * recs[index].nVal)
r++;
else
l--;
}
}


int nRet = pDP[nStart][nEnd];
int nInterval = a[nEnd] - a[nStart];
System.out.print(a[nStart]+" ");

while (nEnd < n)
{
if (a[nEnd] - a[nStart] == nInterval)
{
System.out.print(a[nEnd]+" ");
nStart = nEnd;
}

nEnd++;
}

return nRet;
}
}

class RECORD
{
public int nVal;
public int nIndex;
};

class LessThan implements Comparator<RECORD>
{
@Override
public int compare(RECORD r1, RECORD r2) {
return ((Integer)r1.nVal).compareTo((Integer)r2.nVal);
}

}

Maximum using n moves

Questions Suppose we can compare two arrays like:
{4,2,3} > {3,5,6}
{4,2,3} < {4,3,0}
In each move, you can only switch a number with one of its neighbor.
Given an array and a number n, design an algorithm to make this array maximum using n moves.

Algorithm

1. Find the max number which is at the index <=n+1 in pArray. lets say such number exists at index m where m<=n+1.
2. Swap pArray[m] with pArray[m-1] till m is not equal to 1.
3. n=n-m, pArray++
4. if (n==0) or (pArray == &A[LEN])then exit else go to 1.


public class MaximumUsingNMoves {

public static void MakeMax(int a[], int m)
{
int nCount = m;
for (int i = 0; i < a.length && nCount >= 0; i++)
{
//find the maximum number at right
int nMax = i;
for (int j = i; j < a.length && nCount >= 0 ; j++)
{
nMax = a[j] > a[nMax] ? j : nMax;
nCount--;
}

for (int k = nMax; k != i; k--)
{
int nTmp = a[k];
a[k] = a[k - 1];
a[k - 1] = nTmp;

}
}
}
public static void main(String[] args) {
int a[] = {1,2,3,4,5,6,7,8,9};
MakeMax(a,12);

for (int i = 0; i < a.length; i++)
System.out.print(a[i]+" ");
}
}

Common Meeting point in the grid

Question: There is a town which is a square grid.. every point can be reached from any other point.. there are 10 people in the grid.. find a common meeting ground for them such that the total distance traveled by those 10 people are the least..

Solution: We can find the answer by simplify the question: How to solve it if all we are dealing with a one dimensional array?? How to solve the problem if there is only two people, three people, four people and so on and find the rules!! The answer is to choose the median.

 

import java.util.Arrays;
import java.util.Comparator;


public class GridShortestDistance {
public static void main(String[] args) {
POS poses[] = { new POS(1,2),new POS(4,2),new POS(6,8),new POS(10,32),
new POS(45,3),new POS(22,56),new POS(34,43),new POS(22,12),
new POS(13,33),new POS(54,1),new POS(64,77)};
POS ps = FindMeetingPlace(poses, poses.length);

System.out.println("Meeting place ("+ps.x+","+ps.y+")");

}
static POS FindMeetingPlace(POS a[], int n)
{
POS pos = new POS(0,0);
Arrays.sort(a,new CompX());
pos.x = a[a.length/2].x;
Arrays.sort(a,new CompY());
pos.y = a[a.length/2].y;

return pos;
}
}

class CompX implements Comparator<POS> {
public int compare(POS a, POS b)
{
return ((Integer)a.x).compareTo((Integer)b.x);
}
}
class CompY implements Comparator<POS> {
public int compare(POS a, POS b)
{
return ((Integer)a.y).compareTo((Integer)b.y);
}
}

class POS
{
int x;
int y;
public POS(int a,int b)
{
x = a;
y = b;
}
}

Largest Possible number

Question: Given an array of elements find the largest possible number that can be formed by using the elements of the array.

eg: 10,9 ans: 910
      2,3,5,78 ans: 78532
     100,9  ans: 9100

Solution: Use a special comparator rule and apply it on any sorting.
For number 78 and 782. 78 > 782 because 78782 > 78278

import java.util.Arrays;
import java.util.Comparator;

public class ArrSortComptr {
public static void main(String[] args) {

int array[] = { 782, 78, 221, 212, 2211, 22111, 2122, 2120 };
int[] sortedArr = SortPrimitiveInt(new intComp(), array);
for (int i = 0; i < sortedArr.length; i++) {
System.out.print(sortedArr[i]);
}
}

static int[] SortPrimitiveInt(Comparator<Integer> com, int arr[]) {
Integer[] objInt = intToObject(arr);
Arrays.sort(objInt, com);
return intObjToPrimitive(objInt);

}

static Integer[] intToObject(int[] arr) {
Integer[] a = new Integer[arr.length];
int cnt = 0;
for (int val : arr)
a[cnt++] = new Integer(val);
return a;
}

static int[] intObjToPrimitive(Integer... arr) {
int[] a = new int[arr.length];
int cnt = 0;
for (Integer val : arr)
if (val != null)
a[cnt++] = val.intValue();
return a;

}
}

class intComp implements Comparator<Integer> {
public int compare(Integer a, Integer b) {
return ((Integer) joinRight(b, a)).compareTo((Integer) joinRight(a, b));
}

int joinRight(int a, int b) {
if (0 == b)
return 0;
int nReminder = b % 10;
b = b / 10;
int nRet = joinRight(a, b);

if (0 != nRet)
nRet = nRet * 10 + nReminder;
else
nRet = a;

return nRet;
}
}

Sunday, March 17, 2013

Find a local minimum in a 2-D array

Given an N-by-N array a of N2 distinct integers, design an O(N) algorithm to find a local minimum: an pair of indices i and j such that:

  • a[i][j] < a[i+1][j]
  • a[i][j] < a[i-1][j]
  • a[i][j] < a[i][j+1]
  • a[i][j] < a[i][j-1]

Find the minimum entry in row N/2, say a[N/2][j]. check all entries in its column, if we get smaller entry in column, then recur in the row where smaller column entry belongs.

eg. For array below, N=5:

1  12  3   1  -23  
7 9 8 5 6
4 5 6 -1 77
7 0 35 -2 -4
6 83 1 7 -6


Step 1: The middle row is [4 5 6 -1 77]. ie. row number 3.

Step 2: Minimum entry in current row is -1.


Step 3: Minimum entry in that column would be -2. ( Row 4)


Continue with steps 2-3 till we get the local min.


Iteration 2:


Step 2: Minimum entry in row 4 is –4.


Step 3: Minimum entry in that column would be –23 ( Row 1)


Iteration 3:


Step 2: Minimum entry in row 1 is –23.


Step 3: Minimum entry in that column is –23


Local Minimum would be -23

Top k sums of two sorted arrays

 

You are given two sorted arrays, of sizes n and m respectively. The task is to output the largest k sums of the form a[i]+b[j]

You can solve this problem using Priority Queue is O(k log(m+n)).The approach is do a graph search through the matrix in order of decreasing sums.

Algorithm:

q : priority queue (decreasing) := empty priority queue
add (0, 0) to q with priority a[0] + b[0]
while k > 0:
k--
x := pop q
output x
(i, j) : tuple of int,int := position of x
if i < m:
add (i + 1, j) to q with priority a[i + 1] + b[j]
if j < n:
add (i, j + 1) to q with priority a[i] + b[j + 1]


Analysis:The loop is executed k times.

There is one pop operation per iteration.


There are up to two insert operations per iteration.


The maximum size of the priority queue is O(m + n).


The priority queue can be implemented with a binary heap giving log(size) pop and insert.


Therefore this algorithm is O(k * log(m + n)).



import java.util.PriorityQueue;

public class TopKSums {

private static class FrontierElem implements Comparable<FrontierElem> {
int value;
int aIdx;
int bIdx;

public FrontierElem(int value, int aIdx, int bIdx) {
this.value = value;
this.aIdx = aIdx;
this.bIdx = bIdx;
}

@Override
public int compareTo(FrontierElem o) {
return o.value - value;
}
}

public static void findMaxSum( int [] a, int [] b, int k ) {
Integer [] frontierA = new Integer[ a.length ];
Integer [] frontierB = new Integer[ b.length ];
PriorityQueue<FrontierElem> q = new PriorityQueue<FrontierElem>();
frontierA[0] = frontierB[0]=0;
q.add( new FrontierElem( a[0]+b[0], 0, 0));
while( k > 0 ) {
FrontierElem f = q.poll();
System.out.println( f.value+" "+"("+f.aIdx+","+f.bIdx+") queue Size"+q.size() );
k--;
frontierA[ f.aIdx ] = frontierB[ f.bIdx ] = null;
int fRight = f.aIdx+1;
int fDown = f.bIdx+1;
if( fRight < a.length && frontierA[ fRight ] == null ) {
q.add( new FrontierElem( a[fRight]+b[f.bIdx], fRight, f.bIdx));
frontierA[ fRight ] = f.bIdx;
frontierB[ f.bIdx ] = fRight;
}
if( fDown < b.length && frontierB[ fDown ] == null ) {
q.add( new FrontierElem( a[f.aIdx]+b[fDown], f.aIdx, fDown));
frontierA[ f.aIdx ] = fDown;
frontierB[ fDown ] = f.aIdx;
}
}
}
public static void main(String[] args) {
int[] A = { 21, 20, 19, 18, 17, 16, 15, 14, 13, 11, 10, 9, 7, 6, 5, 4, 3, 2, 1, 0 };
int[] B = { 20, 19, 18, 17, 16, 15, 14, 13, 12, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0 };

findMaxSum(A, B, 10);
}
}

Find if there is any i so that array[i] equals i

Question:  Given a sorted array of distinct integers find the index such that a[i] = i

The brute force approach to solve this problem is O(n). The integers are distinct and sorted.Given i such that array[i] = i you have array[i] - i = 0.

For each j < i you have array[j] - j <= 0 and for j > i you have array[j] - j >= 0 because j vary of 1 at each step but array[j] vary of at least 1 (distinct and sorted numbers).

So on the left it's <=0 on the right it's >= 0. Using binary search approach you can easily find the correct position in O(log n)

 


public class BinarySearchApproach {

public static int findIndex(int arr[])
{
assert(arr != null);
assert(arr.length > 0);
int low = 0;
int high = arr.length-1;
while (low <= high)
{
int middle = (low + high)/2;
if (arr[middle] == middle)
return middle;
if (arr[middle] < middle)
low = middle + 1;
else
high = middle - 1;
}
return -1;
}
public static void main(String[] args) {
int a[] = {-10, -9, -8, 3};
System.out.println("Index is "+findIndex(a));
}
}

Monday, March 11, 2013

Longest Common Prefix

Find the longest common prefix string amongst an array of strings.

We start with the first string as the longest common prefix. We then go through every string in the array and compare the prefix with them. Update (shorten) the prefix if needed.

public class LongestCommonPrefix {
public static String findLongestCommonPrefix(String[] array) {
String prefix;
if (array.length > 0) {
prefix = array[0];
} else {
return "";
}

for (int i = 1; i < array.length; i++) {
String s = array[i];
int j = 0;
for (; j < Math.min(prefix.length(), s.length()); j++) {
if (prefix.charAt(j) != s.charAt(j))
break;
}

prefix = prefix.substring(0, j);
}

return prefix;
}

public static void main(String args[]) {
String str[] = { "hello", "hellohel", "hellohello" };
System.out.println("Longest common prefix is"
+ findLongestCommonPrefix(str));
}
}

Saturday, March 9, 2013

Multiply Strings

Given two numbers represented as strings, return multiplication of the numbers as a string.
Note: The numbers can be arbitrarily large and are non-negative.


public class MultiplyStrings {

static String add(String s1, String s2) {
StringBuffer sb = new StringBuffer();

int carrier = 0;
int p1 = s1.length() - 1;
int p2 = s2.length() - 1;

while (p1 >= 0 || p2 >= 0) {
int a = 0;
int b = 0;

if (p1 >= 0) {
a = s1.charAt(p1) - '0';
p1--;
}

if (p2 >= 0) {
b = s2.charAt(p2) - '0';
p2--;
}
sb.append((a + b + carrier) % 10);
carrier = (a + b + carrier) / 10;
}

return sb.reverse().toString();
}

static String mul(String a, int c, int b) {
StringBuffer sb = new StringBuffer();
int carrier = 0;
for (int i = a.length() - 1; i >= 0; i--) {
int t = (a.charAt(i) - '0') * c;
sb.append((t + carrier) % 10);
carrier = (t + carrier) / 10;
}

sb.reverse();
for (int i = 0; i < b; i++)
sb.append(0);

return sb.toString();
}

public static String multiply(String num1, String num2) {
String result = "";
for (int i = 0; i < num2.length(); i++) {
result = add(result,
mul(num1, num2.charAt(num2.length() - 1 - i) - '0', i));
}

return result;
}

public static void main(String[] args) {
String str1 = "123456789";
String str2 = "987654321";
System.out.println("result is"+multiply(str1, str2));
}
}

Minimum path sum

Given a m * n grid filled with non-negative numbers, find a path from top left to bottom right which minimizes the sum of all numbers along its path. Note: You can only move either down or right at any point in time.

public class MinPathSum {

public int minPathSum(int[][] grid) {
int rows = grid.length;
int cols = grid[0].length;

for (int i = 1; i < rows; i++)
grid[i][0] += grid[i - 1][0];

for (int j = 1; j < cols; j++)
grid[0][j] += grid[0][j - 1];

for (int i = 1; i < rows; i++) {
for (int j = 1; j < cols; j++) {
grid[i][j] = Math.min(grid[i - 1][j], grid[i][j - 1]) + grid[i][j];
}
}
return grid[rows - 1][cols - 1];
}
}

Insert Interval into intervals

Given a set of non-overlapping intervals, insert a new interval into the intervals (merge if necessary). You may assume that the intervals were initially sorted according to their start times.
Example 1:
Given intervals [1,3],[6,9], insert and merge [2,5] in as [1,5],[6,9].
Example 2:
Given [1,2],[3,5],[6,7],[8,10],[12,16], insert and merge [4,9] in as [1,2],[3,10],[12,16]. This is because the new interval [4,9] overlaps with [3,5],[6,7],[8,10].

If the non-overlapping intervals are sorted, we can solve this within O(n). Otherwise, we can sort them first, and do the merge. The time complexity of the latter scenario is O(nlogn). Since the intervals are sorted here, It can be done in O(n) time. We insert the new interval into the set of intervals according to their start value. Then we look back (i.e., left) to see if we can merge. Then we look right (i.e., right) to see if we can merge.

import java.util.ArrayList;
import java.util.List;

public class InsertInterval {

public static List<Interval> mergedIntervals(List<Interval> intervals,
Interval newInterval) {
int startIndex = 0;
for (int i = -1; i < intervals.size(); ++i) {
Interval current = i == -1 ? null : intervals.get(i);
Interval next = i + 1 == intervals.size() ? null : intervals
.get(i + 1);
if ((current == null || current.start <= newInterval.start)
&& (next == null || newInterval.start <= next.start))
startIndex = i + 1;
}
List<Interval> sol = new ArrayList<Interval>();
sol.addAll(intervals);
sol.add(startIndex, newInterval);

int i = startIndex;
// shrink to left
for (; i - 1 >= 0;) {
Interval current = sol.get(i);
Interval previous = sol.get(i - 1);
if (current.start <= previous.end) {
current.start = current.start >= previous.start ? previous.start
: current.start;
current.end = current.end >= previous.end ? current.end
: previous.end;
sol.remove(i - 1);
--i;
} else {
break;
}
}

for (int j = i; j + 1 < sol.size();) {
Interval current = sol.get(j);
Interval next = sol.get(j + 1);
if (current.end >= next.start) {
current.start = current.start >= next.start ? next.start
: current.start;
current.end = current.end >= next.end ? current.end : next.end;
sol.remove(j + 1);
} else {
break;
}
}

return sol;
}

public static void main(String[] args) {
List<Interval> intervals = new ArrayList<Interval>();

intervals.add(new Interval(1, 5));
intervals.add(new Interval(6, 15));
intervals.add(new Interval(20, 21));
intervals.add(new Interval(23, 26));
intervals.add(new Interval(27, 30));
intervals.add(new Interval(35, 40));

Interval another = new Interval(14, 33);

List<Interval> result = mergedIntervals(intervals, another);

for (Interval res : result) {
System.out.println(res.start + "," + res.end);
}
}
}

class Interval {
public int start;
public int end;

public Interval(int start, int end) {
this.start = start;
this.end = end;
}
}

Friday, March 8, 2013

Longest Palindromic subsequence

Given a sequence, find the length of the longest palindromic subsequence in it.

public class LongPalindromeSeq {

// Returns the length of the longest palindromic subsequence in seq
public static int lps(char str[]) {
int n = str.length;
int i, j, cl;
int L[][] = new int[n][n]; // Create a table to store results of subproblems

// Strings of length 1 are palindrome of lentgh 1
for (i = 0; i < n; i++)
L[i][i] = 1;

// Build the table. Note that the lower diagonal values of table are
// useless and not filled in the process. The values are filled in a
// manner similar to Matrix Chain Multiplication DP solution. cl is
// length of
// substring
for (cl = 2; cl <= n; cl++) {
for (i = 0; i < n - cl + 1; i++) {
j = i + cl - 1;
if (str[i] == str[j] && cl == 2)
L[i][j] = 2;
else if (str[i] == str[j])
L[i][j] = L[i + 1][j - 1] + 2;
else
L[i][j] = Math.max(L[i][j - 1], L[i + 1][j]);
}
}

return L[0][n - 1];
}

public static void main(String[] args) {
String seq = "BBABCBCAB";
System.out.println("The lnegth of the LPS is " + lps(seq.toCharArray()));
}

}

Max Sum Increasing sub sequence

Given an array of n positive integers. Write a program to find the sum of maximum sum subsequence of the given array such that the intgers in the subsequence are sorted in increasing order.

public class MaxSumSubsequence {

//maxSumIS() returns the maximum sum of increasing subsequence in arr[] of size n

public static int maxSumIS(int arr[], int n) {
int i, j, max = 0;
int msis[] = new int[n];

// Initialize msis values for all indexes
for (i = 0; i < n; i++)
msis[i] = arr[i];

// Compute maximum sum values in bottom up manner
for (i = 1; i < n; i++)
for (j = 0; j < i; j++)
if (arr[i] > arr[j] && msis[i] < msis[j] + arr[i])
msis[i] = msis[j] + arr[i];

// Pick maximum of all msis values
for (i = 0; i < n; i++)
if (max < msis[i])
max = msis[i];

return max;
}

/* Driver program to test above function */
public static void main(String args[]) {
int arr[] = { 1, 101, 2, 3, 100, 4, 5 };
int n = arr.length;
System.out.println("Sum of maximum sum increasing subsequence is"
+ maxSumIS(arr, n));

}
}

Longest Common subsequence

Given 2 strings, find the longest common subsequence using dynamic programming.

public class LongCommonSubSequence {

//Returns length of LCS for x[0..m-1], y[0..n-1]
public static int lcs(String x, String y) {
int M = x.length();
int N = y.length();

// opt[i][j] = length of LCS of x[i..M] and y[j..N]
int[][] opt = new int[M + 1][N + 1];

// compute length of LCS and all subproblems via dynamic programming
for (int i = M - 1; i >= 0; i--) {
for (int j = N - 1; j >= 0; j--) {
if (x.charAt(i) == y.charAt(j))
opt[i][j] = opt[i + 1][j + 1] + 1;
else
opt[i][j] = Math.max(opt[i + 1][j], opt[i][j + 1]);
}
}

// recover LCS itself and print it to standard output
int i = 0, j = 0;
while (i < M && j < N) {
if (x.charAt(i) == y.charAt(j)) {
System.out.print(x.charAt(i));
i++;
j++;
} else if (opt[i + 1][j] >= opt[i][j + 1])
i++;
else
j++;
}
System.out.println();
return opt[0][0];
}

/* Driver program to test above function */
public static void main(String args[]) {
String str1 = "AGGTAB";
String str2 = "GXTXAYB";
System.out.println("Length of LCS is" + lcs(str1, str2));
}
}

Longest Increasing Subsequence in O(N log N) With elements

The previous post was only printing the length of the Longest Increasing subsequence. This post prints the elements as well in reverse order.

import java.util.Arrays;

public class IncreasingSeqWithArray {

// Binary search
public static int GetCeilIndex(int A[], int T[], int l, int r, int key) {
int m;

while (r - l > 1) {
m = l + (r - l) / 2;
if (A[T[m]] >= key)
r = m;
else
l = m;
}

return r;
}

public static int LongestIncreasingSubsequence(int A[], int size) {
// Add boundary case, when array size is zero
// Depend on smart pointers

int tailIndices[] = new int[size];
int prevIndices[] = new int[size];
int len;

Arrays.fill(prevIndices, -1);

tailIndices[0] = 0;
prevIndices[0] = -1;
len = 1; // it will always point to empty location
for (int i = 1; i < size; i++) {
if (A[i] < A[tailIndices[0]]) {
// new smallest value
tailIndices[0] = i;
} else if (A[i] > A[tailIndices[len - 1]]) {
// A[i] wants to extend largest subsequence
prevIndices[i] = tailIndices[len - 1];
tailIndices[len++] = i;
} else {
// A[i] wants to be a potential condidate of future subsequence
// It will replace ceil value in tailIndices
int pos = GetCeilIndex(A, tailIndices, -1, len - 1, A[i]);

prevIndices[i] = tailIndices[pos - 1];
tailIndices[pos] = i;
}
}
System.out.println("LIS of given input");
for (int i = tailIndices[len - 1]; i >= 0; i = prevIndices[i])
System.out.print(A[i] + " ");

return len;
}

public static void main(String args[]) {
int A[] = { 2, 5, 3, 7, 11, 8, 10, 13, 6 };
int size = A.length;

System.out.println("LIS size " + LongestIncreasingSubsequence(A, size));

}
}

Longest Increasing Subsequence in O(N log N)

In the last post we have seen dynamic programming approach which takes O(n^2) time. We can improve the algorithm to take O(N log N) time.The basic idea behind algorithm is to keep list of LIS of a given length ending with smallest possible element. Constructing such sequence

  1. Find immediate predecessor in already known last elements sequence ( lets say its of length k)
  2. Try to append current element to this sequence and build new better solution for k+1 length

Because in first step you search for smaller value then A[i] the new solution (for k+1) will have last element greater then shorter sequence. Now the improvement happens at the second loop, basically, you can improve the speed by using binary search. Besides the array dp[], let's have another array c[], c is pretty special, c[i] means: the minimum value of the last element of the longest increasing sequence whose length is i.

Java Code:

public class IncreasingSeqInLog {

public static int binary_search(int A[], int len, int key) {
int l = 1, r = len;
int m;
while (r - l > 1) {
m = l + (r - l) / 2;
if (A[m] >= key)
r = m;
else
l = m;
}
return r;
}

public static int LongestIncreasingSubsequenceLength(int array[], int len) {
int sz = 1;
int c[] = new int[len + 1];
int dp[] = new int[len];
c[1] = array[0];
/* at this point, the minimum value of the last element of the size 1
* increasing sequence must be array[0] */
dp[0] = 1;
for (int i = 1; i < len; i++) {
if (array[i] < c[1]) {
c[1] = array[i];
//you have to update the minimum value right now
dp[i] = 1;
} else if (array[i] > c[sz]) {
c[sz + 1] = array[i];
dp[i] = sz + 1;
sz++;
} else {
int k = binary_search(c, sz, array[i]);
// you want to find k so that c[k-1]<array[i]<c[k]
c[k] = array[i];
dp[i] = k;
}
}

return sz;
}

public static void main(String args[]) {
int A[] = { 2, 5, 3, 7, 11, 8, 10, 13, 6 };
int size = A.length;

System.out.println("LIS size "
+ LongestIncreasingSubsequenceLength(A, size));

}
}

Longest Increasing subsequence

Given an array of random numbers. Find longest monotonically increasing subsequence (LIS) in the array.

The longest increasing subsequence problem is a dynamic programming problem that calculates the length of a non-contiguous subsequence from a given sequence. For example, given the sequence:
10, 22, 9, 33, 21, 50, 41, 60
An increasing subsequence is 10,22,33,41. Another increasing subsequence is 9,21,41. The question is to find the length of the longest increasing subsequence, which has size 5 (10,22,33, 50,60). Note that the sequence might not be unique, but you need to find the length of the longest subsequence.
The key is to notice this: let L(j) be the length of the maximum subsequence that ends at value j. By definition, L(j)=L(i)+1 for some i<j, and A[i]<A[j], where A is the array. So, L(j)=max(L(i) for all i<j)+1. Loop from j=0 to j=A.length, and return the largest L(j) for the largest increasing subsequence.

Java Code:

public class DynamicLIS {

/*
* lis() returns the length of the longest increasing subsequence in arr[]
* of size n
*/
public static int lis(int arr[], int n) {
int i, j, max = 0;
int lis[] = new int[n];

/* Initialize LIS values for all indexes */
for (i = 0; i < n; i++)
lis[i] = 1;

/* Compute optimized LIS values in bottom up manner */
for (i = 1; i < n; i++)
for (j = 0; j < i; j++)
if (arr[i] > arr[j] && lis[i] < lis[j] + 1)
lis[i] = lis[j] + 1;

/* Pick maximum of all LIS values */
for (i = 0; i < n; i++)
if (max < lis[i])
max = lis[i];

return max;
}

/* Driver program to test above function */
public static void main(String args[]) {
int arr[] = { 10, 22, 9, 33, 21, 50, 41, 60 };
int n = arr.length;
System.out.println("Length of LIS is " + DynamicLIS.lis(arr, n));
}
}


The time complexity of this algorithm is O(n^2). We will O(nlogn) solution in our next post.

Wednesday, March 6, 2013

Maximum number of intersections

Given a set of intervals, find the interval which has the maximum number of intersections.

Followup to the earlier post, This can be solved in multiple ways.

If the interval is not sparse a good solution might be

public static int getMaxintersection(Interval[] intervals) {
int result = 0;
int[] count;
int min = Integer.MAX_VALUE;
int max = Integer.MAX_VALUE + 1;

// get min and max of the intervals
for (Interval i : intervals) {
if (i.start < min)
min = i.start;
if (i.end > max)
max = i.end;
}

if (min > max)
throw new IllegalArgumentException();

count = new int[max - min + 1];

for (Interval i : intervals)
for (int j = i.start - min; j <= i.end - min; j++)
count[j]++;

for (int i = 0; i < count.length; i++)
if (result < count[i])
result = count[i];

return result;
}


Another approach is sorting the intervals and keeping track of how many intervals have touched the given interval.



1) Construct two n arrays, one is sort by ai, another is sort by bi.
make sure that if ai==aj, then bi<bj, but i before j, the same as b-array.
2) Walk through the b-array for each b, Do a binary search in a-array to find
index, make sure a[index]<=b<a[index+1]
3) find the max(index - i + 1), the the bi is the point we need.


public class MergeIntervals {

public class Interval {
public int start;
public int end;

public Interval(int start, int end) {
super();
this.start = start;
this.end = end;
}
}

public class MyComparatorA implements Comparator {
public int compare(Object o1, Object o2) {
Interval i1 = (Interval) o1;
Interval i2 = (Interval) o2;
return i1.start - i2.start;
}
}

public class MyComparatorB implements Comparator {
public int compare(Object o1, Object o2) {
Interval i1 = (Interval) o1;
Interval i2 = (Interval) o2;
return i1.end - i2.end;
}
}

public int getPoint(ArrayList<Interval> intervals) {
// validation
if (intervals == null || intervals.size() == 0) {
return 0;
}
List<Interval> listA = new ArrayList(intervals);
List<Interval> listB = new ArrayList(intervals);
Collections.sort(listA, new MyComparatorA());
Collections.sort(listB, new MyComparatorB());
int max = 0;
int maxPoint = listB.get(0).end;
for (int i = 0; i < listB.size(); i++) {
Interval interval = listB.get(i);
// find B in sortA. ( use binary search)
int index = search(listA, interval.end);
int count = index - i + 1;
if (count > max) {
max = count;
maxPoint = listB.get(i).end;
}
}
return maxPoint;
}
}

Merging Intervals

Given a collection of intervals, merge all overlapping intervals.
For example,
Given [1,3],[2,6],[8,10],[15,18],
return [1,6],[8,10],[15,18].

Solution:

We first sort the list according to the start value. Then for any interval i in the middle, it has overlap with the next interval j if j.start <= i.end. If so, we know we are about to merge them into a new interval k. And k.start = i.start && k.end = max(i.end, j.end).

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;


public class MergeIntervals {

public class Interval
{
public int start;
public int end;

public Interval(int start, int end) {
super();
this.start = start;
this.end = end;
}
}

public class MyComparator implements Comparator {
public int compare(Object o1, Object o2) {
Interval i1 = (Interval) o1;
Interval i2 = (Interval) o2;
return i1.start - i2.start;
}
}

public ArrayList<Interval> merge(ArrayList<Interval> intervals) {
if (intervals == null)
return null;
ArrayList<Interval> result = new ArrayList<Interval>();
if (intervals.size() == 0)
return result;
if (intervals.size() == 1) {
result.addAll(intervals);
return result;
}
Collections.sort(intervals, new MyComparator());
int start = intervals.get(0).start;
int end = intervals.get(0).end;
for (int i = 1; i < intervals.size(); ++i) {
Interval curr = intervals.get(i);
if (curr.start <= end) {
end = Math.max(end, curr.end);
} else {
result.add(new Interval(start, end));
start = curr.start;
end = curr.end;
}
}
result.add(new Interval(start, end));
return result;
}
}

Sunday, March 3, 2013

submatrix with maximum sum

Given a 2D array, find the maximum sum subarray in it

The usual approach is for every rectangle in the matrix, find the sum and compare it with maximum sum. This takes O(n4) time complexity coz it involves 4 loops.

This can be solved in O(n3) time complexity. To be precise you can solve in ( noOfRows * noOfCols^2) time complexity. The idea is to fix the left and right columns one by one and find the maximum sum contiguous rows for every left and right column pair. We basically find top and bottom row numbers (which have maximum sum) for every fixed left and right column pair. To find the top and bottom row numbers, calculate sun of elements in every row from left to right and store these sums in an array say temp[]. So temp[i] indicates sum of elements from left to right in row i. If we apply Kadane’s 1D algorithm on temp[], and get the maximum sum subarray of temp, this maximum sum would be the maximum possible sum with left and right as boundary columns. To get the overall maximum sum, we compare this sum with the maximum sum.

import java.util.Arrays;

public class MaxSumInRectangle {

public int start = 0, finish = 0;

public int maxSubArraySum(int arr[]) {
// initialize sum, maxSum and start
int sum = 0, maxSum = Integer.MIN_VALUE, i;

// needed if sum NEVER becomes less than 0
start = 0;
// Standard Kadane's algorithm. See following link
for (i = 0; i < arr.length; ++i) {
sum += arr[i];
if (sum < 0) {
sum = 0;
start = i + 1;
} else if (sum > maxSum) {
maxSum = sum;
finish = i;
}
}
return maxSum;
}

// The main function that finds maximum sum rectangle in M[][]
public void findMaxSum(int M[][]) {
// Variables to store the final output
int maxSum = 0, finalLeft = 0, finalRight = 0, finalTop = 0, finalBottom = 0;

int left, right, i;
int temp[] = new int[M.length];
int sum;

// Set the left column
for (left = 0; left < M[0].length; ++left) {
// Initialize all elements of temp as 0
Arrays.fill(temp, 0);

// Set the right column for the left column set by outer loop
for (right = left; right < M[0].length; ++right) {
// Calculate sum between current left and right for every row
// 'i'
for (i = 0; i < M.length; ++i)
temp[i] += M[i][right];

// Find the maximum sum subarray in temp[]. The kadane()
// function
// also sets values of start and finish. So 'sum' is sum of
// rectangle between (start, left) and (finish, right) which is
// the
// maximum sum with boundary columns strictly as left and right.
sum = maxSubArraySum(temp);

// Compare sum with maximum sum so far. If sum is more, then
// update
// maxSum and other output values
if (sum > maxSum) {
maxSum = sum;
finalLeft = left;
finalRight = right;
finalTop = start;
finalBottom = finish;
}
}
}

// Print final values
System.out.println("(Top, Left) (" + finalTop + "," + finalLeft + ")");
System.out.println("(Bottom, Right) (" + finalBottom + "," + finalRight
+ ")");
System.out.println("Max sum is: " + maxSum);
}

public static void main(String args[]) {
int M[][] = { { 1, 2, -1, -4, -20 }, { -8, -3, 4, 2, 1 },
{ 3, 8, 10, 1, 3 }, { -4, -1, 1, 7, -6 } };

new MaxSumInRectangle().findMaxSum(M);
}
}