Monday, August 19, 2019

Calculate the largest rectangle area possible with an array of bars (histogram)


1. Brute Force Solution:
The logic is to consider a bar and go to left and right, till we find a bar of lower height than it.
For eg:
Consider 1 (index=2) in the above diagram. Towards left and right, all the elements either equal or greater than it, so it spans across the entire array, so the area covered = number of elements * height of bar 1 = 7
Consider 4 (index 5). Here we can go till index = 3, towards left and can't move further on right
So area covered = 3 bars * height of bar 4 = 12

public class MaxAreaRectangle {
static public int getMaxArea(int[] ar) {
if(ar == null || ar.length == 0) {
return -1;
}

if(ar.length == 1) {
return ar[0];
}

int maxArea = -1;

for(int i = 0; i < ar.length; i++) {
if(maxArea < ar[i]) {
maxArea = ar[i];
}

for(int j = i - 1; j >= 0 && ar[j] >= ar[i]; j--) {
int area = ar[i] * (i - j + 1);

if(area > maxArea) {
maxArea = area;
}
}
}

return maxArea;
}

static public void main(String[] args) {
int[] ar = new int[] {2, 3, 1, 4, 5, 4, 2};
ar = new int[] {3, 2, 5, 6, 1, 4, 4};
ar = new int[] {1, 1, 1, 1, 1, 7};

System.out.println(getMaxArea(ar));
}
}


2. Optimized Solution with stacks:
The trick is to: push the element's index on to the stack, until we find a lower element than the top of stack.
From here on, pop an element from the stack if it is greater than the next element of array.
For each element that we pop, calculate the area that can be formed with current element index.

Algorithm for an example: {2, 3, 1, 4, 5, 3, 4, 2, 1}

Note: To the stack, we always push the array index of that number (not the actual number)

As long as you encounter an equal or a bigger number than the top number on the stack
When you encounter a smaller number, pop all the elements from the stack, that are greater than it. Then push the current number index on to top of stack.
Because, for eg: in the above problem, for last 2, we need to calculate the distance from first 4.


// Copied from: https://tech.pic-collage.com/algorithm-largest-area-in-histogram-84cc70500f0c
public class MaxAreaRectangle {
static public int getMaxAreaBruteForce(int[] ar) {
if(ar == null || ar.length == 0) {
return -1;
}

if(ar.length == 1) {
return ar[0];
}

int maxArea = -1;

for(int i = 0; i < ar.length; i++) {
if(maxArea < ar[i]) {
maxArea = ar[i];
}

for(int j = i - 1; j >= 0 && ar[j] >= ar[i]; j--) {
int area = ar[i] * (i - j + 1);

if(area > maxArea) {
maxArea = area;
}
}
}

return maxArea;
}

static public int getMaxArea(int[] ar) {
if(ar == null || ar.length == 0) {
return -1;
}

if(ar.length == 1) {
return ar[0];
}

int i = 0, maxArea = 0, topOfStack = 0, width = 0;
Stack stack = new Stack(ar.length);

while(i < ar.length) {
if(stack.isEmpty() || ar[stack.peek()] <= ar[i]) {
stack.push(i++);
} else {
topOfStack = stack.pop();

if(stack.isEmpty()) {
width = i;
} else {
width = i - stack.peek() - 1;
}

int area = ar[topOfStack] * width;

if(area > maxArea) {
maxArea = area;
}
}
}

while(!stack.isEmpty()) {
topOfStack = stack.pop();

if(stack.isEmpty()) {
width = i;
} else {
width = i - stack.peek() - 1;
}

int area = ar[topOfStack] * width;

if(area > maxArea) {
maxArea = area;
}
}

return maxArea;
}

static public void main(String[] args) {
int[] ar = new int[] {2, 3, 1, 4, 5, 4, 2};
ar = new int[] {3, 2, 5, 6, 1, 4, 4};
ar = new int[] {1, 1, 1, 1, 1, 7};
ar = new int[] {2, 3, 1, 4, 5, 3, 4, 2, 1};
ar = new int[] {1, 1, 1};

System.out.println(getMaxArea(ar));
}
}

Saturday, October 14, 2017

Given two arrays (of same length), of which 2nd array contains indices in random order(0 to n-1), replace array with their indexed element values

Q: http://www.geeksforgeeks.org/reorder-a-array-according-to-given-indexes/

Program:

import java.util.Arrays;

class ReplaceWithIndexEle {
        static public void process(int[] ar, int[] ind) {
                for(int i=0; i<ar.length; i++) {
                        int index = ind[i];

                        while(index < i) {
                                index = ind[index];
                        }

                        int temp = ar[i];
                        ar[i] = ar[index];
                        ar[index] = temp;
                }
        }

        static public void main(String[] args) {
                int[] ar = {20, 15, 12, 5, 9, 3, 8, 1};
                int[] ind = {4, 2, 7, 0, 6, 1, 5, 3};

                System.out.println(Arrays.toString(ar));
                process(ar, ind);
                System.out.println(Arrays.toString(ar));
        }
}

Saturday, September 12, 2015

Find lexicographically smallest and largest substring in O(n) time and O(1) space complexity

Given a string and an integer k.
a) find the lexicographically smallest substring of length k in the given String.
b) find the lexicographically largest substring of length k in the given String.

eg: String="welcometojava", k=3

now all possible substrings of length 3 are: wel, elc, lco, com, ome, met, oja, jav, ava
wrt dictionary, the first occuring substring is: "ava" and the last is "wel"


Code:

class LexicoString {
static public void printLex(String str, int k) {
int[] chars = new int[str.length()];

for(int i=0; i<str.length(); i++)
chars[i] = (int) str.charAt(i);

int minSum = 0, minPos = -1, maxSum = 0, maxPos = -1;

int sum = 0;

int multiplier = 1;

for(int i=k-1; i>=0; i--) {
sum = sum + chars[i]*multiplier;
minSum = minSum + 122 * multiplier;

multiplier = multiplier * 10;
}

multiplier = multiplier/10;


for(int i=0; i<chars.length-k+1; i++) {
if(i != 0) {
sum = sum - (chars[i-1] * multiplier);
sum = sum * 10;
sum = sum + chars[i+k-1];
}

System.out.println("i=" + i + ", substring=" + str.substring(i, i+k) + ", sum=" + sum);

if(sum < minSum) {
minSum = sum;
minPos = i;
}

if(sum > maxSum) {
maxSum = sum;
maxPos = i;
}
}

System.out.println("Positions: min=" + minPos + ", max=" + maxPos);
}

static public void main(String[] args) {
printLex("welcometojava", 3);
}
}

Friday, September 4, 2015

List all zero sum sub arrays in the given array containing zero/positive/negative numbers

Problem:

Given an array containing negative/zero/positive elements.
Now list all the start and end positions of the sub arrays, whose sum is equal to zero.

For eg:
{2, -1, 0, 1, 1, -1, -2}

Output:
start=2, end=2
start=1, end=3
start=1, end=5
start=4, end=5
start=0, end=6

Algorithm:

maintain HashMap with key as current sum and value as a list of index positions
3 cases possible for every element:
1. current element is zero: output is: start=currentPosition, end=currentPosition
2. current sum is zero: output is: start=0, end=currentPosition
3. current sum is already present in the hashMap, which means that the sub array formed by positions "hashMap.get(currentSum)+1" and "currentPosition" sum is zero. so print all such possibilities with hashMap values

If the sum is not present in the hashMap, then insert (sum, {currentPosition})
if the sum is already present, then insert (sum, {previously inserted positions, currentPosition})

Program:

import java.util.List;
import java.util.ArrayList;
import java.util.Map;
import java.util.HashMap;

class PrintPositions {
static public void printPos(int[] in) {
Map<Integer, List<Integer>> map = new HashMap<Integer, List<Integer>>();

int sum = 0;

for(int i=0; i<in.length; i++) {
sum = sum + in[i];

if(in[i] == 0)
System.out.println("start=" + i + ", end=" + i);
else if(sum == 0)
System.out.println("start=0, end=" + i);
else {
if(map.containsKey(sum)) {
List<Integer> positions = map.get(sum);

for(int pos : positions)
System.out.println("start=" + (pos+1) + ", end=" + i);
}
}

if(map.get(sum) == null) {
List<Integer> list = new ArrayList<Integer>();
list.add(i);
map.put(sum, list);
} else {
List<Integer> list = map.get(sum);
list.add(i);
}
}
}

static public void main(String[] args) {
PrintPositions pp = new PrintPositions();

pp.printPos(new int[]{2, -1, 0, 1, 1, -1, -2});
}
}

output:

start=2, end=2
start=1, end=3
start=1, end=5
start=4, end=5
start=0, end=6
start=1, end=7
start=4, end=7
start=6, end=7

Thursday, July 9, 2015

Making maximum profit in stock market: Buying and Selling

Problem Statement:

You are given an array, which contains the prices of a stock in a day.
You have to find the buy, sell pairs, so that you will make a maximum profit, by buying and selling the stock.

For eg: {100, 180, 260, 310, 50, 40, 535, 695}
--> First you can buy at: 100
      Sell at 310 ==> profit = (310-100) = 210
--> Buy at: 40
      Sell at: 695 ==> profit = (695-40) = 655

Algorithm:

Starting from first element, algorithm has to find the buy and sell prices.
Note that we have to buy at less price and sell at high price.
So we have to find the (low buy, high sell) price pairs.

1. First find an element, after which the sequence should be increasing.
2. Next find the element, for which all its left elements are lower from the buy price.
This becomes one pair.
3. Now starting from next price after the above sell price, find the first element, after which the sequence should be increasing.
4. Again, find the next element, for which all its left elements are lower from the buy price.

Continue this process until the array end is reached.

Code:


class StockMarket {
        static public void stockBuySell(int[] price, int n) {
                if(n == 1) return;

                int count = 0;

                //columns corresponds to buy and sell elements
                int[][] ints = new int[n/2+1][2];

                int i = 0;

                while(i < n-1) {
                        while( (i < n-1) && (price[i+1] <= price[i]))
                                i++;

                        if(i == n-1)
                                break;

                        ints[count][0] = i++;

                        while((i < n) && (price[i] >= price[i-1]))
                                i++;

                        ints[count][1] = i-1;

                        count++;
                }

                if(count == 0)
                        System.out.println("You cant make profit on this day");
                else
                        for(int j=0; j<count; j++)
                                System.out.println("Buy: " + price[ints[j][0]] + ", sell: " + price[ints[j][1]]);
        }

        static public void main(String[] args) {
                int[] price = {100, 180, 260, 310, 50, 40, 535, 695};

                stockBuySell(price, price.length);
        }
}


Output:

Buy: 100, sell: 310
Buy: 40, sell: 695

Complexity:

Time Complexity: O(n)

Space Complexity: O(n) (we can avoid this space and do it in O(1) as well, i.e, printing at the end of the while loop)

Wednesday, July 8, 2015

Linked List: Cycle detection: Floyd Cycle Algorithm

Floyd Cycle Algorithm:

As per this algorithm, if there is a cycle in Linked List, then the fast and slow pointers must meet at some point in the cycle and the start of the cycle can be find by, keeping a pointer at meeting location and moving another pointer from start of linked list, makes the two pointers to reach at the start of the cycle.

Lets prove it...


Proof:


Case 1: Fast pointer made one cycle:
So the slow pointer moved a distance of "x+y"
and fast pointer moved a distance of "x+y+z+y"

and if slow pointer moves a distance of "d", then fast pointer moves a distance of "2d", since is fast pointer moves two times faster than slow pointer.
So: distance traveled by fast ptr = 2 * distance traveled by slow ptr
==> x+y+z+y = 2 * (x+y)
x+2y + z = 2x + 2y
x+z = 2x
==> x = z

This proves that x and z are equal. So keeping one ptr at the meeting point of pointers, and moving other pointer from start will make them to meet at the start of the cycle.

Case 2: Fast pointer made two cycles:

==> fast pointer distance from start = x + y + 2(z+y)
==> slow pointer distance from start = x + y

==> x + y + 2 (z+y) = 2(x+y)
==> x + 3y + 2z = 2x + 2y
==> x = y + 2z
==> x = z  + (y+z)

since, if we start from a point in cycle and move (z+y) distance, we will be at the same point again. It means that with respect cycle, we didnt move at all.
So we can make "y+z" as zero
==> x = z

Similarly we can prove for n number of cycles as well.



Tuesday, June 23, 2015

Find two Repeated or Non-Repeated numbers in the given array

Problem 1: 
There are n+2 elements, which are in the range of 1 to n. All are unique, except two numbers. Find the two repeated numbers.

eg: {4, 2, 4, 5, 2, 3, 1}
output: 2, 4

Algorithm:
Given array: int[] ar

Find XOR of all elements in input array and all numbers from 1 to n:
XOR = ar[0] ^ ar[1] ^ ... ar[n+1] ^ ar[n+2] ^ 0 ^ 1 ... ^ n

Now Get the right most set bit in this XOR Result
right_most_set_bit = XOR & (~(XOR-1))

One of the missing number will be "XOR of all array elements and all numbers from 1 to n, which are having the righ_most_set_bit set in them"
Other missing number will be "XOR of all array elements and all numbers from 1 to n, which are not having the righ_most_set_bit set in them"

Program:

public class FindRepeatedNos {
static public void main(String[] args) {
int[] ar = {4, 2, 4, 5, 2, 3, 1};
int n = 5;

int x = 0, y = 0;

int xor = 0;

for(int i=0; i<ar.length; i++)
xor = xor ^ ar[i];

for(int i=1; i<=n; i++)
xor = xor ^ i;

//Get the right most digit
int right_most_bit = xor & (~(xor-1));

for(int i=0; i<ar.length; i++) {
if((ar[i] & right_most_bit) == 0)
x = x ^ ar[i];
else
y = y ^ ar[i];
}

for(int i=1; i<=n; i++) {
if((i & right_most_bit) == 0)
x = x ^ i;
else
y = y ^ i;
}

System.out.println(x);
System.out.println(y);
}
}


Problem 2:

Given an array containing n elements. All the elements are repeated twice, except two numbers, which occurred only once. Find those two numbers. No range specified for input elements.

eg: {2, 4, 7, 9, 2, 4}
output: 7, 9

Algorithm:

It is similar to above algorithm, except that we dont have 1 to n numbers here. So only one for loop for all xor operations.

Program:

public class FindNonRepeatedNos {
         static public void main(String[] args) {
int[] ar = {2, 4, 7, 9, 2, 4};

int x = 0, y = 0, xor = 0;

for(int i=0; i<ar.length; i++)
xor = xor ^ ar[i];

int right_most_set = xor & (~(xor-1));

for(int i=0; i<ar.length; i++) {
if((ar[i] & right_most_set) == 0)
x = x ^ ar[i];
else
y = y ^ ar[i];
}

System.out.println(x);
System.out.println(y);
}
}