Longest Increasing Subsequence from each element - algorithm

Given a list {x_i}, I want to find the longest increasing subsequence starting from each element such that the starting element is included in the subsequence.
The obvious way would to do this would be to perform the usual longest increasing subsequence algorithm on each element, giving O(n^2 logn). Can this be beaten?

You can use DP and bring it down to O(n^2).
Let the input be x1, x2, ..., xn
Let f1, f2, ..., fn be the length of longest increasing sequence starting from ith element. Initialize all of them to 1.
Now,
for i = n-1, n-2, .... , 1:
for j = i,i+1,...,n:
if x[i]<x[j]:
fi=max(fi, fj+1)
If you want actual sequence in addition to the length, keep track of another variable g1,g2, ..., gn where gi is the next element to follow. Initialize gis to NULL.
for i = n-1, n-2, .... , 1:
for j = i,i+1,...,n:
if x[i]<x[j]:
if fi<fj+1:
fi=fj+1
gi=j
Once you have gs, I will leave you to figure out how to enumerate the sequence starting from a particular location.

A more efficient algorithm would rely on sharing the same data structure for each iteration instead of restarting the algorithm each time. One way to do this would be to find the longest decreasing subsequence of the reverse of your input list. This should give you a data structure that gives you constant-time access to the predecessor for each element, and the length of the subsequence starting at that element.
For each starting element: if it's in the longest decreasing subsequence, follow its predecessors to the end. If it's not, find the element that is larger and to the right of it, and has the most predecessors, and follow that element's predecessors.
This would give a worst-case time complexity of O(N^2), but at least that is needed to output the results anyway.

int main(){
int arr[]={1,10,5,12,17,18,19};
int t[]={1,0,0,0,0,0,0};
int i,j;
vector<int>v[7];
v[0].push_back(1);
for(i =1;i<7;i++){
for(j =0;j<i;j++){
if(arr[j]<arr[i]){
if(t[j]>=t[i]){
t[i]=t[j]+1;
v[i].push_back(arr[j]);
}
}
}
if(i==j){
v[i].push_back(arr[i]);
}
}
for(i=0;i<7;i++){
for(j=0;j<v[i].size();j++){
cout<<v[i][j]<<" ";
}
cout<<endl;
}
return 0;
}
This is c++ code ,time complexity is N^2.I will come up with more elegant(using map with pair) solution rather than this . That will be nlogn order.I didnt write that code here because that will depends on data density .If data will be dense then i will write that approach otherwise it will always work fine.

Related

Minimal Number of Extract + Inserts required to sort a list

Context
this problem arises from trying to minimize number of expensive function calls
Problem Definition
Please note that extract_and_insert != swap. In particular, we take the element from position "from", insert it at position "to", and SHIFT all intermediate elements.
int n;
int A[n]; // all elements are integer and distinct
function extract_and_insert(from, to) {
int old_value = A[from]
if (from < to) {
for(int i = from; i < to; ++i)
A[i] = A[i+1];
A[to] = old_value;
} else {
for(int i = from; i > to; --i)
A[i] = A[i-1];
A[to] = old_value;
}
}
Question
We know there are O(n log n) algorithms for sorting a list of numbers.
Now: is there an O(n log n) function, which returns the minimum number of calls to extract_and_insert required to sort the list?
The answer is Yes.
This problem is essentially equivalent to finding the longest increasing subsequence (LIS) in an array, and you can use algorithms to solve that.
Why is this question equivalent to longest increasing subsequence?
Because each extract_and_insert operation will, at its most effective use, correct the relative position of exactly one element in the array. In other words, when we consider the length of the longest increasing subsequence of the array, each operation will increase that length by 1. So, the minimum number of required calls is:
length_of_array - length_of_LIS
and therefore by finding the length of LIS, we will be able to find the minimum number of operations required.
Do read up the linked Wikipedia page to see how to implement the algorithm.

How does algorithm for Longest increasing subsequence [O(nlogn)] work?

I found algorithm mentioned in The Hitchhiker’s Guide to the Programming Contests (note: this implementation assumes there are no duplicates in the list):
set<int> st;
set<int>::iterator it;
st.clear();
for(i=0; i<n; i++) {
st.insert(array[i]); it=st.find(array[i]);
it++; if(it!=st.end()) st.erase(it);
}
cout<<st.size()<<endl;
It's an algorithm to find longest increasing subsequence in O(NlogN). If I try to work it with few test cases, it seems to work. But I still couldn't figure out its correctness logic. Also, it doesn't look so intuitive to me.
Can anyone help me gain insight as to why this algorithm works correctly?
Statement: For each i, length of current set is equal to the length of the largest increasing subsequence.
Proof: Lets use the method of induction:
Base case : Trivially true.
Induction hypothesis: Suppose we have processed i-1 elements and the length of the set is LIS[i-1], i.e the length of the LIS possible with first i-1 elements.
Induction step: Inserting an element array[i] in the set will result in two cases.
A[i] >= set.last() : In this case A[i] will be the last element in the set and hence the LIS[i] = LIS[i-1]+1.
A[i] < set.last() : In this case we insert A[i] into the set and knock off element just greater than A[i] in the sorted order. LIS[i] = LIS[i-1] + 1(adding A[i]) - 1 (removing one elem > A[i]). Which is true. Hence proved.
To explain the big picture. Inserting A[i] into the set will either add to the LIS[i-1] or will create a LIS of its own, which will be the elements from 0th position to the position of the ith element.
How to determine the longest increasing subsequence using dynamic programming?
Please read my explanation there first. If it is still not clear, read the following:
The algorithm keeps the lowest possible ending number for LIS of every length. By keeping the lowest numbers, you can extend the LIS in a maximal way. I know this is not a proof, but maybe it will be intuitive for you.

find maximum sum of n elements in an array such that not more than k elements are adjacent

Almost the same as this:
find maximum sum of elements in an array such that not more than k elements are adjacent
except there is a limit of n elements we can choose. How to modify the DP algorithm to make it work for this?
Add new dimension of DP function:
f[i, j, l] - max sum for first i elements, if used j total elements and last l elements in this sum.
well, let me make it more clearly.
question: find maximum sum of n elements in an array such that not more than K elements are adjacent
let int f[i][j][k] means the maximum sum for first i elements, using j total elements and the last k elements are used. let bool g[i][j][k] denotes whether it is possible to get certain combination. eg. g[1][1][2] is false. this is important because without restrict, f may generate impossible answers.
initially, memset f and g to be all zeros and set g[0][0][0] to be true. we can use forward recurrence to solve this DP problem. obviously, each time you encounter a number, you have two choices: choose it, or abadon it. thay gives out the recurrence formula:
f[i][j][k] can infer f[i+1][j+1][k+1], or
f[i][j][k] can infer f[i+1][j][0]
so, the pseudo code can be as follow:
memset(f,0,sizeof(f));
memset(g,0,sizeof(g));
g[0][0][0]=true;
for (int i=0;i<array.size();i++)
for (int j=0;j<=n;j++)
for (int k=0;k<=K;k++) if (g[i][j][k]) {
f[i+1][j][0]=max(f[i+1][j][0],f[i][j][k]);
f[i+1][j+1][k+1]=max(f[i+1][j+1][k+1],f[i][j][k]+array[i]);
g[i+1][j][0]=true;
g[i+1][j+1][k+1]=true;
}
and the final result will be:
ans=0;
for (i=0;i<=K;i++)
ans=max(ans,f[array.size()][n][i]);
return ans;
above gives exactly j elements. if you want to get at most j elements, you can change it in this way:
ans=0;
for (i=0;i<=n;i++)
for (j=0;j<=K;j++)
ans=max(ans,f[array.size()][i][j]);
return ans;

finding longest similar subsequence in a string

Suppose I want to find the longest subsequence such that first half of subsequence is same as second half of it.
For example: In a string abkcjadfbck , result is abcabc as abc is repeated in first and second half of it. In a stirng aaa, result is aa.
This task may be treated as a combination of two well known problems.
If you know in advance some point between two halves of the subsequence, you just need to find the best match for two strings. This is Pairwise alignment problem. Various dynamic programming methods solve it in O(N2) time.
To find a point where the string should be split optimally, you can use Golden section search or Fibonacci search. These algorithms have O(log N) time complexity.
In a first pass over inputString, we can count how often each character occurs, and remove those with occurrence one.
input: inputString
data strucutres:
Set<Triple<char[], Integer, Integer>> potentialSecondWords;
Map<Char, List<Integer>> lettersList;
for the characters c with increasing index h in inputString do
if (!lettersList.get(c).isEmpty()) {
for ((secondWord, currentIndex, maxIndex) in potentialSecondWords) {
if (there exists a j in lettersList.get(c) between currentIndex and maxIndex) {
update (secondWord, currentIndex, maxIndex) by adding c to secondWord and replacing currentIndex with j;
}
}
if potentialSecondWords contains a triple whose char[] is equal to c, remove it;
put new Triple with value (c,lettersList.get(c).get(0), h-1) into potentialSecondWords;
}
lettersList.get(c).add(h);
}
find the largest secondWord in potentialSecondWords and output secondWord twice;
So this algorithm passes once over the array, creating for each index, where it makes sense, a Triple representing the potential second word starting at the current index, and updates all potential second words.
With a suitable list implementation and n being the size of inputString, this algorithm has worst case runtime O(n²), e.g. for a^n.

Finding All possible Longest Increasing subsequence

I want to find all possible Longest Increasing Subsequences in a given string.
For eg: Given string is qapbso
Here the length of longest increasing subsequence is 3.
I want to find all possible longest subsequence of length 3. i.e "abs", "aps", "abo".
I am using Dynamic Programming but I am only getting one LIS. I want to list down all of them.
So the typical DP solution to this will produce an array in which you know what is the longest possible subsequence starting at a given position i let's say that you have and array with length n in which dp[i] stores the length of the longest non-decreasing subseq that starts with the element with index i.
Now printing all the LNDSS(longest non-decreasing subsequences) is easiest to be done using a recursion. First find the actual length of the LNDSS by seleting the greast value in dp. Next start the recursion from each element in dp that has the maximum value in dp(these may be more then one). The recursion from a given index should print all the sequences starting from the current index that have length equal to the value dp[i]:
int st[1000];
int st_index
void rec(int index) {
if (dp[index] == 1) {
cout << "Another sequence:\n";
for (int i = 0; i < st_index; ++i) {
cout << st[i] << endl;
}
}
for (int j = index + 1; j < n; ++j) {
if (dp[j] == dp[index] - 1 && a[j] >= a[index]) {
st[st_index++] = a[j];
rec(j);
st_index--;
}
}
}
This is example code in c++(hope it is understandable in other languages as well). I have a global stack called stack that keeps the elements we have already added. It has size 1000 assuming you will never have more then 1000 elements in the LNDSS but this can be increased. The solution does not have the best possible design, but I have focused on making it simple rather then well designed.
Hope this helps.
Given this graph where all nodes are connected to the nodes that have both higher value and appear later in the sequence of letters of your input string:
You want to find the longest path from START to END. This is equivalent to the shortest path if all segments have negative length of -1.
Reference on longest path problem: http://en.wikipedia.org/wiki/Longest_path_problem
In 2000 Sergei Bespamyatnikh and Michael Segal proposed an algorithm for finding all longest increasing subsequences of a given permutation. The algorithm uses a Van Emde Boas tree and has a time complexity of O(n + Kl(p)) and space complexity of O(n), where n is the length of a permutation p, l(p) is the length of its longest increasing subsequence and K is the number of such subsequences.
See the paper in the ACM Digital Library or search the web for "Enumerating longest increasing subsequences and patience sorting" to get a free PDF.

Resources