Longest Increasing Subsequence (LIS):

Problem statement:
Our aim here is to find out longest increasing subsequence from the given sequence/array of integers. Note that the increasing subsequence need not to be continuous.
Let’s trace below scenario,
If the original sequence is {15, 27, 14, 38, 26, 55, 46, 65, 85} then, possible increasing subsequence would be,


Original Sequence. (Input)
Increasing Subsequence. (output)
Length
1.
{15, 27, 14, 38, 26, 55, 46, 65, 85}
{15, 27, 38, 55, 65, 85}
6.
2.
{15, 27, 14, 38, 26, 55, 46, 65, 85}
{14, 26, 46, 65, 85}
5.

Approach:
We can solve this problem using dynamic programming. I’m going to create two arrays. One to store reference of previous element(arr1), another will store temporary sequence of increasing elements(arr2).

Case-I.
Append current element to the subsequence only if the previous element is smaller than the current one.
(Note: Current element is the element at the ith position while running the loop over an input sequence.)

Current Element
Subsequence
Final Subsequence
Length
{4}
{1, 2, 3}
{1, 2, 3, 4}
4

Here, Element 4 will hold the index of 3, 3 will index of 2 and so on and so forth as shown below,

1
-1(default)
2
Index=0
3
Index=1
4
Index=2

Case-II.
Find the celling in case, current element is smaller than the last element and greater than the first element. And just replace the ceiling with the current element.
(Note: Current element is the element at the ith position while running the loop over an input sequence.)

Current Element
Subsequence
Final Subsequence
Length
{3}, assumed index=7
{1, 5, 7}
{1, 3, 7}
3

Here, Element 7 will hold the index of 3(which is 7), 3 will index of 1 and so on and so forth as shown below,

1
-1(default)
3
Index=0
7
Index=7




Case-III.
If the current element is smaller than the first element of the subsequence. Then replace the first element with the current element
(Note: Current element is the element at the ith position while running the loop over an input sequence.)

Current Element
Subsequence
Final Subsequence
Length
{0}, assumed index=6
{1, 2, 3}
{0, 2, 3}
3


Here, Element 3 will hold the index of 2, 2 will index of 0(which is 6) and so on and so forth as shown below,

0
-1(default)
2
Index=6
3
Index=1

If I run through the given input sequence using above logic then, I’ll end up with below mentioned array which is pointing to the index of its previous element.

Loop-i
Current
Element
Arr2
Arr1(Initialized with -1)
Length
Loop-0
15
{15}
{-1, -1, -1, -1, -1, -1, -1, -1, -1}
1
Loop-1
27
{15, 27}
{-1, 0, -1, -1, -1, -1, -1, -1, -1}
2
Loop-2
14
{14, 27}
{-1, 0, -1, -1, -1, -1, -1, -1, -1}
2
Loop-3
38
{14, 27, 38)
{-1, 0, -1, 1, -1, -1, -1, -1, -1}
3
Loop-4
26
{14, 26, 38)
{-1, 0, -1, 1, 2, -1, -1, -1, -1}
3
Loop-5
55
{14, 26, 38, 55)
{-1, 0, -1, 1, 2, 3, -1, -1, -1}
4
Loop-6
46
(14, 26, 38, 46}
{-1, 0, -1, 1, 2, 3, 3, -1, -1}
4
Loop-7
65
{14, 26, 38, 46, 65}
{-1, 0, -1, 1, 2, 3, 3, 6, 7}
5
Loop-8
85
{14, 26, 38, 46, 65, 85}
{-1, 0, -1, 1, 2, 3, 3, 6, 7}
6

So, my Longest Increasing Subsequence would be,

Runtime Complexity:

  • To find ceiling from the sorted array, we are using binary search (log(n)).
  • Also, we are iterating through an entire sequence of n elements.
So in worst-case Time complexity of this algorithm would be O(n logn).


Code:

package com.mayank4java;

public class LISAlgorithm {

private Data tempArray[];
private int sequencePointerArray[];
private int lengthOfSequence = 0;

public LISAlgorithm() {}

private static class Data {
int index;
int value;
}

public int findCeiling(Data array[], int searchElement, int max) {
int min = 0;
int avg = 0;
if (searchElement < array[0].value)
return 0;

for (int j = 0; j < max; j++) {
if (max >= min)
avg = (max + min) / 2;
if (searchElement == array[min].value)
return array[min].index;
else if (searchElement == array[max].value)
return array[max].index;
else if (searchElement == array[avg].value)
return array[avg].index;
else if (max - min == 1)
return max;
else if (searchElement > array[avg].value)
min = avg;
else if (searchElement < array[avg].value)
max = avg;
}
return avg;
}

public void doLIS(int[] intSequence) {
sequencePointerArray = new int[intSequence.length];
tempArray = new Data[intSequence.length];
sequencePointerArray[0] = -1;

Data data = new Data();
data.value = intSequence[0];
data.index = 0;
tempArray[0] = data;

for (int i = 1; i < intSequence.length; i++) {
sequencePointerArray[i] = -1;// initializing elements to -1.
if (intSequence[i] > tempArray[lengthOfSequence].value) {
++lengthOfSequence;
data = new Data();
data.value = intSequence[i];
data.index = i;
tempArray[lengthOfSequence] = data;
sequencePointerArray[i] = tempArray[lengthOfSequence - 1].index;
} else {
int index = findCeiling(tempArray, intSequence[i], lengthOfSequence);
data = new Data();
data.value = intSequence[i];
data.index = i;
tempArray[index] = data;
if (index != 0)
sequencePointerArray[i] = tempArray[index - 1].index;
}
}
int pointer = tempArray[lengthOfSequence].index;
for (int i = 0; i < sequencePointerArray.length; i++) {
System.out.println(intSequence[pointer]);
pointer = sequencePointerArray[pointer];
if (pointer == -1)
break;
}
}

public static void main(String[] args) {
int sequence[] = { -11, -5, -10, 0, 12, 13, 1, 2, 3 };
/*int sequence[] = { 0, 8, 4, 12, 2, 10, 6, 14, 1, 9, 5, 13, 3, 11, 7, 15 };*/
/*int sequence[] = {0, 12,13,1,2,3};*/
/*int sequence[] = {0,7,8,1};*/
LISAlgorithm lis = new LISAlgorithm();
lis.doLIS(sequence);
}
}


That is it!😃
Hope this post helped you.Also don't forget to share and leave your comments below.

Comments

Popular posts from this blog

How to Run OR Debug Map Reduce algorithm using eclipse IDE, without installing Hadoop & HDFS on Windows OS.

BFS to solve 'Snake and Ladder' Problem.