Algorithm reorder array according to given index
a[] = [50, 40, 70, 60, 90]
index[] = [3, 0, 4, 1, 2]
a= [60,50,90,40,70]
in O(n) and With out extra array/spaces
You'll need space for a temp variable and loop counters / indices. The usual "reorder" according to algorithm is also going to change index[] back to {0, 1, 2, 3, 4}.
Hint, noting the ordering of indices in index[].
{0, 1, 2, 3, 4}
index[] = {3, 0, 4, 1, 2}
The reordering can be done by following the "cycles". Start with index[0], and note the "cycles" if you look at index[0], then index[index[0]], and so on ...
// 1st cycle
index[0] == 3 // cycle starts at 0
index[3] == 1
index[1] == 0 // end of cycle since back at 0
// 2nd cycle
index[2] == 4 // cycle starts at 2
index[4] == 2 // end of cycle since back at 2
Example C code:
#include <stdio.h>
static int A[] = {50, 40, 70, 60, 90};
static int I[] = {3, 0, 4, 1, 2};
int main()
{
int i, j, k;
int tA;
/* reorder A according to I */
/* every move puts an element into place */
/* time complexity is O(n) */
for(i = 0; i < sizeof(A)/sizeof(A[0]); i++){
if(i != I[i]){
tA = A[i];
j = i;
while(i != (k = I[j])){
A[j] = A[k];
I[j] = j;
j = k;
}
A[j] = tA;
I[j] = j;
}
}
for(i = 0; i < sizeof(A)/sizeof(A[0]); i++)
printf("%d\n", A[i]);
return 0;
}
The same algorithm, but using swaps instead of moves (this is slower method).
#include <stdio.h>
#define swap(a, b) {(a)^=(b); (b)^=(a); (a)^=(b);}
static int A[] = {50, 40, 70, 60, 90};
static int I[] = {3, 0, 4, 1, 2};
int main()
{
int i, j, k;
/* reorder A according to I */
/* every swap puts an element into place */
/* last swap of a cycle puts both elements into place */
/* time complexity is O(n) */
for(i = 0; i < sizeof(A)/sizeof(A[0]); i++){
if(i != I[i]){
j = i;
while(i != (k = I[j])){
swap(A[j], A[k]);
I[j] = j;
j = k;
}
I[j] = j;
}
}
for(i = 0; i < sizeof(A)/sizeof(A[0]); i++)
printf("%d\n", A[i]);
return 0;
}
Related
The question is:
"Given an array A only contains integers Return the number of subarrays that contain at least k different numbers. Subarrays cannot be duplicated."
Example:
input array = {1, 2, 3, 4, 2} k = 3
output: 4
Explanation:
the number of the Subarray with at least K different numbers should be 4,
which are [1, 2, 3] [2, 3, 4] [3, 4, 2] [1, 2, 3, 4]
Right now what I can do is just find about the number of the subarray with exactly K different numbers:
class Solution {
public int subarraysWithKDistinct(int[] A, int K) {
return atMostK(A, K) - atMostK(A, K - 1);
}
private int atMostK(int[] A, int K) {
int i = 0, res = 0;
Map<Integer, Integer> count = new HashMap<>();
for (int j = 0; j < A.length; ++j) {
if (count.getOrDefault(A[j], 0) == 0) K--;
count.put(A[j], count.getOrDefault(A[j], 0) + 1);
while (K < 0) {
count.put(A[i], count.get(A[i]) - 1);
if (count.get(A[i]) == 0) K++;
i++;
}
res += j - i + 1;
}
return res;
}
}
But when the input be:
array = {1, 2, 3, 4, 2} k = 2
my code will not work correctly, but I don't know where to change. Any thoughts? Thanks!
Update: thanks to #MBo and others' answers, I used 2 pointers to fix this problem, but still cannot get the right answer with:
array = {1, 2, 3, 4, 2} k = 3 -> output: 6 (should be 4)
It looks like there are some duplicated substrings be counted, but I don't know how to fix it.
class Solution {
public static void main(String[] args) {
int[] A = {1, 2, 3, 4, 2};
int k = 3;
int res = helper(A, k);
System.out.println(res);
// output is 6, but should be 4
}
private static int helper(int[] A, int k) {
if (A == null || A.length == 0) return 0;
int n = A.length;
int res = 0;
int differentNumbers = 0;
Map<Integer, Integer> counter = new HashMap<>();
int j = 0; // j - 1 is the right point
for (int i = 0; i < n; i ++) {
while (j < n && differentNumbers < k) {
int numOfThisNumber = counter.getOrDefault(A[j], 0);
counter.put(A[j], numOfThisNumber + 1);
if (counter.get(A[j]) == 1) {
differentNumbers ++;
}
j ++;
}
if (differentNumbers == k) {
res += n - j + 1;
}
counter.put(A[i], counter.get(A[i]) - 1);
if (counter.get(A[i]) == 0) {
differentNumbers --;
}
}
return res;
}
}
You can combine your hashmap approach with method of two pointers (indices).
Set both indices into 0 and move right one, updating hashmap counts for values at the right end of interval until hashmap size reaches K. Fix right index.
Now move left index, decreasing counts corresponding to the values at left end. Before every step (including left=0) add size-right to result, because all subarrays starting from left and ending after right, do contain needed number of elements.
When some count becomes 0, remove value from hashmap, and fix left index.
Repeat with right index and so on.
Given an array and we can add or subtract some element an amount less than K to make the longest increasing subarray
Example: An array a=[6,4,3,2] and K=1; we can subtract 1 from a[2]; add 1 to a[4] so the array will be a=[6,3,3,3] and the LIS is [3,3,3]
An algorithm of complexity O(n) is possible, by considering a "state" approach.
For each index i, the state corresponds to the three values that we can get: A[i]-K, A[i], A[i]+K.
Then, for a given index, for each state s = 0, 1, 2, we can calculate the maximum increasing sequence length terminating at this state.
length[i+1][s] = 1 + max (length[i][s'], if val[i][s'] <= val[i+1][s], for s' = 0, 1, 2)
We can use the fact that length[i][s] is increasing with s.
In practice, if we are only interesting to know the final maximum length, we don't need to memorize all the length values.
Here is a simple C++ implementation, to illustrate this algorithm. It only provides the maximum length.
#include <iostream>
#include <vector>
#include <array>
#include <string>
struct Status {
std::array<int, 3> val;
std::array<int, 3> l_seq; // length sequences
};
int longuest_ascending_seq (const std::vector<int>& A, int K) {
int max_length = 0;
int n = A.size();
if (n == 0) return 0;
Status previous, current;
previous = {{A[0]-K, A[0]-K, A[0]-K}, {0, 0, 0}};
for (int i = 0; i < n; ++i) {
current.val = {A[i]-K, A[i], A[i] + K};
for (int j = 0; j < 3; ++j) {
int x = current.val[j];
if (x >= previous.val[2]) {
current.l_seq[j] = previous.l_seq[2] + 1;
} else if (x >= previous.val[1]) {
current.l_seq[j] = previous.l_seq[1] + 1;
} else if (x >= previous.val[0]) {
current.l_seq[j] = previous.l_seq[0] + 1;
} else {
current.l_seq[j] = 1;
}
}
if (current.l_seq[2] > max_length) max_length = current.l_seq[2];
std::swap (previous, current);
}
return max_length;
}
int main() {
std::vector<int> A = {6, 4, 3, 2, 0};
int K = 1;
auto ans = longuest_ascending_seq (A, K);
std::cout << ans << std::endl;
return 0;
}
I have a relatively big (say, 5000 rows by 8000 columns) and sparse matrix that is stored in compressed row storage (CRS). I am trying to get its compressed column storage (CCS) form.
Is there already an standard algorithm for doing this? One option could be reconstructing the entire matrix (40 million entries) from the CRS and then using an straightforward algorithm to obtain its CCS. However, the time complexity of this is terrible and I plan on using this algorithm on even bigger matrices. Any other ideas on how to do this?
Probably not as efficient as the Numerical Recipes code, but I came up with this that seems to work:
#include <stdio.h>
#include <string.h>
#define COLS 6
#define SIZE(a) (sizeof(a)/sizeof(*(a)))
int main() {
float f[] = {10,-2, 3, 9, 3, 7, 8, 7, 3, 8, 7, 5, 8, 9, 9,13, 4, 2, 1};
int c[] = { 0, 4, 0, 1, 5, 1, 2, 3, 0, 2, 3, 4, 1, 3, 4, 5, 1, 4, 5};
int r[] = { 0, 2, 5, 8, 12, 16, 19};
float nf[SIZE(f)];
int nc[COLS+1] = {0};
int nr[SIZE(f)];
int nn[COLS+1];
int rr[SIZE(f)];
for (int k = 0, i = 0; i < SIZE(r); i++)
for (int j = 0; j < r[i+1] - r[i]; j++)
rr[k++] = i;
for (int i = 0; i < SIZE(f); i++)
nc[c[i]+1]++;
for (int i = 1; i <= COLS; i++)
nc[i] += nc[i-1];
memcpy(nn, nc, sizeof(nc));
for (int i = 0; i < SIZE(f); i++) {
int x = nn[c[i]]++;
nf[x] = f[i];
nr[x] = rr[i];
}
for (int i = 0; i < SIZE(nf); i++) printf("%2.0f ", nf[i]);
putchar('\n');
for (int i = 0; i < SIZE(nr); i++) printf("%2d ", nr[i]);
putchar('\n');
for (int i = 0; i < SIZE(nc); i++) printf("%2d ", nc[i]);
putchar('\n');
return 0;
}
There seems to be something like a standard approach as one algorithm is described in Numerical Recipes. I'll cite the code here which should give you the idea, whereas for more details you should consult chapter 2.7. of the third edition.
NRsparseMat NRsparseMat::transpose() const {
Int i,j,k,index,m=nrows,n=ncols;
NRsparseMat at(n,m,nvals); //Initialized to zero.
//First find the column lengths for AT , i.e. the row lengths of A.
VecInt count(m,0); //Temporary counters for each row of A.
for (i=0;i<n;i++)
for (j=col_ptr[i];j<col_ptr[i+1];j++) {
k=row_ind[j];
count[k]++;
}
for (j=0;j<m;j++) //Now set at.col_ptr. 0th entry stays 0.
at.col_ptr[j+1]=at.col_ptr[j]+count[j];
for(j=0;j<m;j++) //Reset counters to zero.
count[j]=0;
for (i=0;i<n;i++) //Main loop.
for (j=col_ptr[i];j<col_ptr[i+1];j++) {
k=row_ind[j];
index=at.col_ptr[k]+count[k]; //Element’s position in column of AT .
at.row_ind[index]=i;
at.val[index]=val[j];
count[k]++; //Increment counter for next element in that column.
}
return at;
}
For my personal use, I usually rewrite code from Numerical Recipes by removing it's specific typedefs (such as Int, VecInt), rename, reformat, etc.
The problem I'm trying to solve is how do we find all the integer sets [a1, a2, ... ,am] so that
a1 + a2 + ... + am = N
and with the constraint ai >= 1
For example if M = 4, and N = 7 there are three answers
[1,1,1,4]
[1,1,2,3]
[1,2,2,2]
Since you have to print all the sets that sum to N. You can employ a complete search algorithm using recursion. In the following code, M is the number of numbers in the set and N is the sum required.
int M;
int N;
void run(){
M = 4;
N = 7;
int[] arr = new int[M];
print(arr, 0, N, 1);
}
// req holds the required sum for the numbers in the array from arr[from]
// to arr[M-1].
// "last" holds the last value that we had put in the array.
// The first call to the array will be with last=1.
void print(int[] arr, int from, int req, int last){
// Reached the end of the array and sum required 0.
if(from==M && req==0){
System.out.println(Arrays.toString(arr));
return;
}
// Either reached the end of the array but sum is not equal to N
// Or if we have not reached the end of the array but sum has already
// become more than or equal to N.
if(from==M || req<=0){
return;
}
for(int i=last; i<=req; i++){
arr[from] = i;
print(arr, from+1, req-i, i);
}
}
Output for M=4 and N=7:
[1, 1, 1, 4]
[1, 1, 2, 3]
[1, 2, 2, 2]
Output for M=3 and N=10:
[1, 1, 8]
[1, 2, 7]
[1, 3, 6]
[1, 4, 5]
[2, 2, 6]
[2, 3, 5]
[2, 4, 4]
[3, 3, 4]
Answer for the problem in the link, just got accepted.
The idea is simple, assume that we know the maximum value for each section is X, and we want to find a way to divide these cabinets to achieve that , we can greedily divide them as follow:
Starting from first cabinet, iterating through each cabinet, until the total from first to ith cabinet is greater than X. So this is the first section, similarly, we can select other sections. This greedy will always find a solution (if exists).
Finally, we can using binary search to adjust the value of X, decrease X if we can find a way to divide the cabinets, or increase X if we cannot find one.
Here is the code in Java:
public class FairWorkload {
public int getMostWork(int[] folders, int workers) {
int[] data = new int[folders.length];
data[0] = folders[0];
for (int i = 1; i < data.length; i++) {
data[i] = data[i - 1] + folders[i];
}
if (workers == 1) {
return data[data.length - 1];
}
int start = 0;
int end = data[data.length - 1];
int result = Integer.MAX_VALUE;
while (start <= end) {
int mid = (start + end) / 2;
int index = 0;
for (int k = 0; k < workers && index < data.length; k++) {
int less = index > 0 ? data[index - 1] : 0;
int temp = index;
for (int i = index; i < data.length; i++) {
if (data[i] - less <= mid) {
temp = i;
} else {
break;
}
}
// System.out.println(data[temp] - less + " " + mid);
if(data[temp] - less > mid){
index = -1;
break;
}
index = temp + 1;
}
//System.out.println(mid + " " + index);
if (index != data.length) {
start = mid + 1;
} else {
result = Math.min(result, mid);
end = mid - 1;
}
}
return result;
}
public static void main(String[] args) {
int[] data = {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1000};
System.out.println(new FairWorkload().getMostWork(data, 2));
}
}
One possible solution uses a counting technique, finding the rightmost term that satisfies [i] <= [length-1] - 2, and then flattening out all other terms to the right as much as possible, keeping a[i] <= a[i+1].
import java.util.Arrays;
public class test {
public static void main(String[] args) {
test t = new test();
t.go();
}
private void go() {
int w = 3;
int sum = 10;
int[] terms = new int[w];
for (int i = 0; i < terms.length; i++) {
terms[i] = 1;
}
terms[w-1] = sum - w + 1;
System.out.println(Arrays.toString(terms));
for (int i = right_index(terms); i>=0; i = right_index(terms)) {
terms[i]++;
int a = terms[i];
int overflow = -1;
// balance all the terms to the right
for (int j = i+1; j < terms.length-1; j++) {
overflow += terms[j] - a;
terms[j] = a;
}
terms[terms.length-1] += overflow;
System.out.println(Arrays.toString(terms));
}
}
// find the rightmost index i, where [i] <= [ia.length-1] - 2
private int right_index(int[] ia) {
int max = ia[ia.length-1];
for (int i = ia.length - 1; i >= 0; i--) {
if (ia[i] <= max - 2)
return i;
}
return -1;
}
}
You are given a sequence of numbers and you need to find a longest increasing subsequence from the given input(not necessary continuous).
I found the link to this(Longest increasing subsequence on Wikipedia) but need more explanation.
If anyone could help me understand the O(n log n) implementation, that will be really helpful. If you could explain the algo with an example, that will be really appreciated.
I saw the other posts as well and what I did not understand is:
L = 0
for i = 1, 2, ... n:
binary search for the largest positive j ≤ L such that X[M[j]] < X[i] (or set j = 0 if no such value exists)
above statement, from where to start binary search? how to initialize M[], X[]?
A simpler problem is to find the length of the longest increasing subsequence. You can focus on understanding that problem first. The only difference in the algorithm is that it doesn't use the P array.
x is the input of a sequence, so it can be initialized as:
x = [0, 8, 4, 12, 2, 10, 6, 14, 1, 9, 5, 13, 3, 11, 7, 15]
m keeps track of the best subsequence of each length found so far. The best is the one with the smallest ending value (allowing a wider range of values to be added after it). The length and ending value is the only data needed to be stored for each subsequence.
Each element of m represents a subsequence. For m[j],
j is the length of the subsequence.
m[j] is the index (in x) of the last element of the subsequence.
so, x[m[j]] is the value of the last element of the subsequence.
L is the length of the longest subsequence found so far. The first L values of m are valid, the rest are uninitialized. m can start with the first element being 0, the rest uninitialized. L increases as the algorithm runs, and so does the number of initialized values of m.
Here's an example run. x[i], and m at the end of each iteration is given (but values of the sequence are used instead of indexes).
The search in each iteration is looking for where to place x[i]. It should be as far to the right as possible (to get the longest sequence), and be greater than the value to its left (so it's an increasing sequence).
0: m = [0, 0] - ([0] is a subsequence of length 1.)
8: m = [0, 0, 8] - (8 can be added after [0] to get a sequence of length 2.)
4: m = [0, 0, 4] - (4 is better than 8. This can be added after [0] instead.)
12: m = [0, 0, 4, 12] - (12 can be added after [...4])
2: m = [0, 0, 2, 12] - (2 can be added after [0] instead of 4.)
10: m = [0, 0, 2, 10]
6: m = [0, 0, 2, 6]
14: m = [0, 0, 2, 6, 14]
1: m = [0, 0, 1, 6, 14]
9: m = [0, 0, 1, 6, 9]
5: m = [0, 0, 1, 5, 9]
13: m = [0, 0, 1, 5, 9, 13]
3: m = [0, 0, 1, 3, 9, 13]
11: m = [0, 0, 1, 3, 9, 11]
7: m = [0, 0, 1, 3, 7, 11]
15: m = [0, 0, 1, 3, 7, 11, 15]
Now we know there is a subsequence of length 6, ending in 15. The actual values in the subsequence can be found by storing them in the P array during the loop.
Retrieving the best sub-sequence:
P stores the previous element in the longest subsequence (as an index of x), for each number, and is updated as the algorithm advances. For example, when we process 8, we know it comes after 0, so store the fact that 8 is after 0 in P. You can work backwards from the last number like a linked-list to get the whole sequence.
So for each number we know the number that came before it. To find the subsequence ending in 7, we look at P and see that:
7 is after 3
3 is after 1
1 is after 0
So we have the subsequence [0, 1, 3, 7].
The subsequences ending in 7 or 15 share some numbers:
15 is after 11
11 is after 9
9 is after 6
6 is after 2
2 is after 0
So we have the subsequences [0, 2, 6, 9, 11], and [0, 2, 6, 9, 11, 15] (the longest increasing subsequence)
One of the best explanation to this problem is given by MIT site.
http://people.csail.mit.edu/bdean/6.046/dp/
I hope it will clear all your doubts.
based on FJB's answer, java implementation:
public class Lis {
private static int[] findLis(int[] arr) {
int[] is = new int[arr.length];
int index = 0;
is[0] = index;
for (int i = 1; i < arr.length; i++) {
if (arr[i] < arr[is[index]]) {
for (int j = 0; j <= index; j++) {
if (arr[i] < arr[is[j]]) {
is[j] = i;
break;
}
}
} else if (arr[i] == arr[is[index]]) {
} else {
is[++index] = i;
}
}
int[] lis = new int[index + 1];
lis[index] = arr[is[index]];
for (int i = index - 1; i >= 0; i--) {
if (is[i] < is[i + 1]) {
lis[i] = arr[is[i]];
} else {
for (int j = is[i + 1] - 1; j >= 0; j--) {
if (arr[j] > arr[is[i]] && arr[j] < arr[is[i + 1]]) {
lis[i] = arr[j];
is[i] = j;
break;
}
}
}
}
return lis;
}
public static void main(String[] args) {
int[] arr = new int[] { 0, 8, 4, 12, 2, 10, 6, 14, 1, 9, 5, 13, 3, 11,
7, 15 };
for (int i : findLis(arr)) {
System.out.print(i + "-");
}
System.out.println();
arr = new int[] { 1, 9, 3, 8, 11, 4, 5, 6, 4, 19, 7, 1, 7 };
for (int i : findLis(arr)) {
System.out.print(i + "-");
}
System.out.println();
}
}
Below is the O(NLogN) longest increasing subsequence implementation:
// search for the index which can be replaced by the X. as the index can't be
//0 or end (because if 0 then replace in the findLIS() and if it's greater than the
//current maximum the just append)of the array "result" so most of the boundary
//conditions are not required.
public static int search(int[] result, int p, int r, int x)
{
if(p > r) return -1;
int q = (p+r)/2;
if(result[q] < x && result[q+1]>x)
{
return q+1;
}
else if(result[q] > x)
{
return search(result, p, q, x);
}
else
{
return search(result, q+1, r, x);
}
}
public static int findLIS(int[] a)
{
int[] result = new int[a.length];
result[0] = a[0];
int index = 0;
for(int i=1; i<a.length; i++)
{
int no = a[i];
if(no < result[0]) // replacing the min number
{
result[0] = no;
}
else if(no > result[index])//if the number is bigger then the current big then append
{
result[++index] = no;
}
else
{
int c = search(result, 0, index, no);
result[c] = no;
}
}
return index+1;
}
Late to the party, but here's a JavaScript implementation to go along with the others.. :)
var findLongestSubsequence = function(array) {
var longestPartialSubsequences = [];
var longestSubsequenceOverAll = [];
for (var i = 0; i < array.length; i++) {
var valueAtI = array[i];
var subsequenceEndingAtI = [];
for (var j = 0; j < i; j++) {
var subsequenceEndingAtJ = longestPartialSubsequences[j];
var valueAtJ = array[j];
if (valueAtJ < valueAtI && subsequenceEndingAtJ.length > subsequenceEndingAtI.length) {
subsequenceEndingAtI = subsequenceEndingAtJ;
}
}
longestPartialSubsequences[i] = subsequenceEndingAtI.concat();
longestPartialSubsequences[i].push(valueAtI);
if (longestPartialSubsequences[i].length > longestSubsequenceOverAll.length) {
longestSubsequenceOverAll = longestPartialSubsequences[i];
}
}
return longestSubsequenceOverAll;
};
Based on #fgb 's answer, I implemented the algorithm using c++ to find the longest strictly increasing sub-sequence. Hope this will be somewhat helpful.
M[i] is the index of the last element of the sequence whose length is i, P[i] is the index of the previous element of i in the sequence, which is used to print the whole sequence.
main() is used to run the simple test case: {0, 8, 4, 12, 2, 10, 6, 14, 1, 9, 5, 13, 3, 11, 7, 15}.
#include <vector>
using std::vector;
int LIS(const vector<int> &v) {
int size = v.size(), max_len = 1;
// M[i] is the index of the last element of the sequence whose length is i
int *M = new int[size];
// P[i] is the index of the previous element of i in the sequence, which is used to print the whole sequence
int *P = new int[size];
M[0] = 0; P[0] = -1;
for (int i = 1; i < size; ++i) {
if (v[i] > v[M[max_len - 1]]) {
M[max_len] = i;
P[i] = M[max_len - 1];
++max_len;
continue;
}
// Find the position to insert i using binary search
int lo = 0, hi = max_len - 1;
while (lo <= hi) {
int mid = lo + ((hi - lo) >> 1);
if (v[i] < v[M[mid]]) {
hi = mid - 1;
} else if (v[i] > v[M[mid]]) {
lo = mid + 1;
} else {
lo = mid;
break;
}
}
P[i] = P[M[lo]]; // Modify the previous pointer
M[lo] = i;
}
// Print the whole subsequence
int i = M[max_len - 1];
while (i >= 0) {
printf("%d ", v[i]);
i = P[i];
}
printf("\n");
delete[] M, delete[] P;
return max_len;
}
int main(int argc, char* argv[]) {
int data[] = {0, 8, 4, 12, 2, 10, 6, 14, 1, 9, 5, 13, 3, 11, 7, 15};
vector<int> v;
v.insert(v.end(), data, data + sizeof(data) / sizeof(int));
LIS(v);
return 0;
}
The O(N lg N) solution comes from patience sorting of playing card. I found this from my code comment and hence sharing here. I believe it would be really easier to understand for everyone how it works. Also you can find all possible longest increasing sub-sequence list if you understand well.
https://www.cs.princeton.edu/courses/archive/spring13/cos423/lectures/LongestIncreasingSubsequence.pdf
Code:
vector<int> lisNlgN(vector<int> v) {
int n = v.size();
vector<int> piles = vector<int>(n, INT_MAX);
int maxLen = 0;
for(int i = 0; i < n; i++) {
int pos = lower_bound(piles.begin(), piles.end(), v[i]) - piles.begin();
piles[pos] = v[i];
maxLen = max(maxLen, pos+1); // Plus 1 because of 0-based index.
}
// // Print piles for debug purpose
// for (auto x : piles) cout << x << " ";
// cout << endl;
//
// // Print position for debug purpose
// for (auto x : position) cout << x << " ";
// cout << endl;
vector<int> ret = vector<int>(piles.begin(), piles.begin() + maxLen);
return ret;
}
Code:
vector<vector<int>> allPossibleLIS(vector<int> v) {
struct Card {
int val;
Card* parent = NULL;
Card(int val) {
this->val = val;
}
};
auto comp = [](Card* a, Card* b) {
return a->val < b->val;
};
int n = v.size();
// Convert integers into card node
vector<Card*> cards = vector<Card*>(n);
for (int i = 0; i < n; i++) cards[i] = new Card(v[i]);
vector<Card*> piles = vector<Card*>(n, new Card(INT_MAX));
vector<Card*> lastPileCards;
int maxLen = 0;
for(int i = 0; i < n; i++) {
int pos = lower_bound(piles.begin(), piles.end(), new Card(v[i]), comp) - piles.begin();
piles[pos] = cards[i];
// Link to top card of left pile
if (pos == 0) cards[i]->parent = NULL;
else cards[i]->parent = piles[pos-1];
// Plus 1 because of 0-based index.
if (pos+1 == maxLen) {
lastPileCards.push_back(cards[i]);
} else if (pos+1 > maxLen) {
lastPileCards.clear();
lastPileCards.push_back(cards[i]);
maxLen = pos + 1;
}
}
// Print for debug purpose
// printf("maxLen = %d\n", maxLen);
// printf("Total unique lis list = %d\n", lastPileCards.size());
vector<vector<int>> ret;
for (auto card : lastPileCards) {
vector<int> lis;
Card* c = card;
while (c != NULL) {
lis.push_back(c->val);
c = c->parent;
}
reverse(lis.begin(), lis.end());
ret.push_back(lis);
}
return ret;
}