/**
* Greedy algorithm for longest increasing subsequence. Time complexity is nlg(n).
* for short description of the algorithm and proof of correctness visit
* https://www.cs.princeton.edu/courses/archive/spring13/cos423/lectures/LongestIncreasingSubsequence.pdf
*/
public List<Integer> longestStrictlyIncreasingSubsequenceListWithGreedyAlgorithm(int[] arr){
List<Stack<Integer>> piles = new ArrayList<>();
for(int i =0 ; i < arr.length ; i++)
addValue(arr[i], piles);
List<Integer> ret = new ArrayList<>();
for(Stack<Integer > s : piles)
ret.add(s.peek());
return ret;
}
/**
* inserts the integer to the appropriate position among piles. The position may be a new stack added to the piles.
* @param i arbitrary integer
* @param piles a list of stacks of integers such that top elements of each stack is in sorted order.
*/
private void addValue(int i, List<Stack<Integer>> piles) {
//simply do a binary search among top of each pile
//at this point it is known that top of each stack is sorted.
int lo = 0;
int hi = piles.size()-1;
//handle if the integer should be a new pile
if(piles.size() == 0 || i >= piles.get(hi).peek()){
Stack<Integer> newStack = new Stack<>();
newStack.push(i);
piles.add(newStack);
return;
}
while(hi!=lo){
int mid = (hi+lo) >>> 1; //taking average
if(piles.get(mid).peek() <= i)
lo = mid+1;
else
hi = mid;
}
piles.get(hi).push(i);
}