/* A direct translation from https://e...content-available-to-author-only...a.org/wiki/Longest_increasing_subsequence
*
* by Khang Hoang Nguyen(kevinhng86)
*/
import java.util.Random ;
public class Main {
public static void main
( String [ ] args
) { long startTime, endTime, duration;
int tCase = 1000000 ,
lenEach = 15 ;
/* Benchmark section */
// Generate random strings, so the compiler doesn't optimize it away.
String tests
[ ] = randomStr
( tCase, lenEach
) ;
startTime
= System .
nanoTime ( ) ; for ( int i = 0 ; i < tCase; i++ ) {
wordInSeq( tests[ i] ) ;
}
duration = ( endTime - startTime) ;
System .
out .
printf ( "Benchmark score(ms) test with %d test cases, each random string is len %d: " , tCase, lenEach
) ; System .
out .
printf ( "%d(Millisecond)" , duration
/ 1000000 ) ; /* End Benchmark */
/* Result test section */
System .
out .
println ( "Test Input:" ) ; System .
out .
println ( "xvwzzzxyxx => " + wordInSeq
( "xvwzzzxyxx" ) ) ; System .
out .
println ( "abdb => " + wordInSeq
( "abdb" ) ) ; System .
out .
println ( "xvwzxz => " + wordInSeq
( "xvwzxz" ) ) ; /* End result test section. */
}
int P[ ] = new int [ s.length ( ) ] ;
int M[ ] = new int [ s.length ( ) + 1 ] ;
int L = 0 ;
for ( int i = 0 ; i < s.length ( ) ; i++ ) {
// Binary search for the largest positive j ≤ L
// such that X[M[j]] <= X[i]
int lo = 1 ;
int hi = L;
while ( lo <= hi ) {
// This is equal to round up for / 2
int mid = ( ( lo+ hi) >> 1 ) + ( ( lo + hi) & 1 ) ;
// This was change
// < : low to high no repeat
// <= : low to high repeating
// > : high to low no repead
// >= : high to low repeating
if ( s.charAt ( M[ mid] ) < s.charAt ( i) )
lo = mid+ 1 ;
else
hi = mid- 1 ;
}
// After searching, lo is 1 greater than the
// length of the longest prefix of X[i]
int newL = lo;
// The predecessor of X[i] is the last index of
// the subsequence of length newL-1
P[ i] = M[ newL- 1 ] ;
M[ newL] = i;
if ( newL > L) {
// If we found a subsequence longer than any we've
// found yet, update L
L = newL;
}
}
// Reconstruct the longest increasing subsequence
char S[ ] = new char [ L] ;
int k = M[ L] ;
for ( int i = L - 1 ; i > - 1 ; i-- ) {
S[ i] = s.charAt ( k) ;
k = P[ k] ;
}
}
private static String [ ] randomStr
( int amount,
int lenEach
) {
for ( int i = 0 ; i < amount; i++ ) {
char temp[ ] = new char [ lenEach] ;
for ( int j = 0 ; j < lenEach; j++ ) {
temp[ j] = ( char ) ( random.nextInt ( 26 ) + 97 ) ;
}
}
return output;
}
}
LyogQSBkaXJlY3QgdHJhbnNsYXRpb24gZnJvbSBodHRwczovL2UuLi5jb250ZW50LWF2YWlsYWJsZS10by1hdXRob3Itb25seS4uLmEub3JnL3dpa2kvTG9uZ2VzdF9pbmNyZWFzaW5nX3N1YnNlcXVlbmNlIAogKgogKiBieSBLaGFuZyBIb2FuZyBOZ3V5ZW4oa2V2aW5obmc4NikKICovCgppbXBvcnQgamF2YS51dGlsLlJhbmRvbTsKCnB1YmxpYyBjbGFzcyBNYWluIHsKICAgIHB1YmxpYyBzdGF0aWMgdm9pZCBtYWluKFN0cmluZ1tdIGFyZ3MpIHsKICAgICAgICBsb25nIHN0YXJ0VGltZSwgZW5kVGltZSwgZHVyYXRpb247CiAgICAgICAgaW50IHRDYXNlID0gMTAwMDAwMCwKICAgICAgICAgICAgbGVuRWFjaCA9IDE1OwoKICAgICAgICAvKiBCZW5jaG1hcmsgc2VjdGlvbiAqLwogICAgICAgIC8vIEdlbmVyYXRlIHJhbmRvbSBzdHJpbmdzLCBzbyB0aGUgY29tcGlsZXIgZG9lc24ndCBvcHRpbWl6ZSBpdCBhd2F5LgogICAgICAgIFN0cmluZyB0ZXN0c1tdID0gcmFuZG9tU3RyKHRDYXNlLCBsZW5FYWNoKTsKCiAgICAgICAgc3RhcnRUaW1lID0gU3lzdGVtLm5hbm9UaW1lKCk7CiAgICAgICAgZm9yICggaW50IGkgPSAwOyBpIDwgdENhc2U7IGkrKyl7CiAgICAgICAgICAgIHdvcmRJblNlcSh0ZXN0c1tpXSk7CiAgICAgICAgfSAgICAKICAgICAgICBlbmRUaW1lID0gU3lzdGVtLm5hbm9UaW1lKCk7CiAgICAgICAgZHVyYXRpb24gPSAoZW5kVGltZSAtIHN0YXJ0VGltZSk7IAoKICAgICAgICBTeXN0ZW0ub3V0LnByaW50ZigiQmVuY2htYXJrIHNjb3JlKG1zKSB0ZXN0IHdpdGggJWQgdGVzdCBjYXNlcywgZWFjaCByYW5kb20gc3RyaW5nIGlzIGxlbiAlZDogIiwgdENhc2UsIGxlbkVhY2ggKTsKICAgICAgICBTeXN0ZW0ub3V0LnByaW50ZigiJWQoTWlsbGlzZWNvbmQpIiwgZHVyYXRpb24vMTAwMDAwMCk7CiAgICAgICAgU3lzdGVtLm91dC5wcmludGxuKCk7CiAgICAgICAgLyogRW5kIEJlbmNobWFyayAqLwoKICAgICAgICAvKiBSZXN1bHQgdGVzdCBzZWN0aW9uICovIAogICAgICAgIFN5c3RlbS5vdXQucHJpbnRsbigpOwogICAgICAgIFN5c3RlbS5vdXQucHJpbnRsbigiVGVzdCBJbnB1dDoiKTsKICAgICAgICBTeXN0ZW0ub3V0LnByaW50bG4oInh2d3p6enh5eHggPT4gIiArIHdvcmRJblNlcSgieHZ3enp6eHl4eCIpKTsKICAgICAgICBTeXN0ZW0ub3V0LnByaW50bG4oImFiZGIgPT4gIiArIHdvcmRJblNlcSgiYWJkYiIpKTsKICAgICAgICBTeXN0ZW0ub3V0LnByaW50bG4oInh2d3p4eiA9PiAiICsgd29yZEluU2VxKCJ4dnd6eHoiKSk7CiAgICAgICAgLyogRW5kIHJlc3VsdCB0ZXN0IHNlY3Rpb24uICovIAogICAgfQoKICAgIHByaXZhdGUgc3RhdGljIFN0cmluZyB3b3JkSW5TZXEoU3RyaW5nIHMpIHsKCiAgICAgICAgaW50IFBbXSA9IG5ldyBpbnRbcy5sZW5ndGgoKV07CiAgICAgICAgaW50IE1bXSA9IG5ldyBpbnRbcy5sZW5ndGgoKSsxXTsKCiAgICAgICAgaW50IEwgPSAwOwogICAgICAgIGZvciAoaW50IGkgPSAwOyBpIDwgcy5sZW5ndGgoKTsgaSsrICkgIHsKICAgICAgICAgICAgLy8gQmluYXJ5IHNlYXJjaCBmb3IgdGhlIGxhcmdlc3QgcG9zaXRpdmUgaiDiiaQgTAogICAgICAgICAgICAvLyBzdWNoIHRoYXQgWFtNW2pdXSA8PSBYW2ldCiAgICAgICAgICAgIGludCBsbyA9IDE7CiAgICAgICAgICAgIGludCBoaSA9IEw7CgogICAgICAgICAgICB3aGlsZSAoIGxvIDw9IGhpICl7CiAgICAgICAgICAgICAgICAvLyBUaGlzIGlzIGVxdWFsIHRvIHJvdW5kIHVwIGZvciAvIDIKICAgICAgICAgICAgICAgIGludCBtaWQgPSAoKGxvK2hpKSA+PiAxKSArICgobG8gKyBoaSkgJiAxKTsKCiAgICAgICAgICAgICAgICAvLyBUaGlzIHdhcyBjaGFuZ2UKICAgICAgICAgICAgICAgIC8vIDwgIDogbG93IHRvIGhpZ2ggbm8gcmVwZWF0CiAgICAgICAgICAgICAgICAvLyA8PSA6IGxvdyB0byBoaWdoIHJlcGVhdGluZwogICAgICAgICAgICAgICAgLy8gPiAgOiBoaWdoIHRvIGxvdyBubyByZXBlYWQKICAgICAgICAgICAgICAgIC8vID49IDogaGlnaCB0byBsb3cgcmVwZWF0aW5nIAogICAgICAgICAgICAgICAgaWYgKHMuY2hhckF0KE1bbWlkXSkgPCBzLmNoYXJBdChpKSkKICAgICAgICAgICAgICAgICAgICBsbyA9IG1pZCsxOwogICAgICAgICAgICAgICAgZWxzZQogICAgICAgICAgICAgICAgICAgIGhpID0gbWlkLTE7CiAgICAgICAgICAgIH0KICAgICAgICAgICAgLy8gQWZ0ZXIgc2VhcmNoaW5nLCBsbyBpcyAxIGdyZWF0ZXIgdGhhbiB0aGUKICAgICAgICAgICAgLy8gbGVuZ3RoIG9mIHRoZSBsb25nZXN0IHByZWZpeCBvZiBYW2ldCiAgICAgICAgICAgIGludCBuZXdMID0gbG87CgogICAgICAgICAgICAvLyBUaGUgcHJlZGVjZXNzb3Igb2YgWFtpXSBpcyB0aGUgbGFzdCBpbmRleCBvZiAKICAgICAgICAgICAgLy8gdGhlIHN1YnNlcXVlbmNlIG9mIGxlbmd0aCBuZXdMLTEKICAgICAgICAgICAgUFtpXSA9IE1bbmV3TC0xXTsKICAgICAgICAgICAgTVtuZXdMXSA9IGk7CgogICAgICAgICAgICBpZiAobmV3TCA+IEwpewogICAgICAgICAgICAgICAgLy8gSWYgd2UgZm91bmQgYSBzdWJzZXF1ZW5jZSBsb25nZXIgdGhhbiBhbnkgd2UndmUKICAgICAgICAgICAgICAgIC8vIGZvdW5kIHlldCwgdXBkYXRlIEwKICAgICAgICAgICAgICAgIEwgPSBuZXdMOwogICAgICAgICAgICB9CiAgICAgICAgfQoKICAgICAgICAvLyBSZWNvbnN0cnVjdCB0aGUgbG9uZ2VzdCBpbmNyZWFzaW5nIHN1YnNlcXVlbmNlCiAgICAgICAgY2hhciBTW10gPSBuZXcgY2hhcltMXTsKICAgICAgICBpbnQgayA9IE1bTF07CiAgICAgICAgZm9yIChpbnQgaSA9IEwgLSAxOyBpID4gLTE7IGktLSApewogICAgICAgICAgICBTW2ldID0gcy5jaGFyQXQoayk7CiAgICAgICAgICAgIGsgPSBQW2tdOwogICAgICAgIH0KICAgICAgICByZXR1cm4gbmV3IFN0cmluZyhTKTsKICAgIH0KCiAgICBwcml2YXRlIHN0YXRpYyBTdHJpbmdbXSByYW5kb21TdHIoIGludCBhbW91bnQsIGludCBsZW5FYWNoICl7CiAgICAgICAgU3RyaW5nIG91dHB1dFtdID0gbmV3IFN0cmluZ1thbW91bnRdOwogICAgICAgIFJhbmRvbSByYW5kb20gPSBuZXcgUmFuZG9tKCk7CgogICAgICAgIGZvciAoIGludCBpID0gMDsgaSA8IGFtb3VudDsgaSsrKXsKICAgICAgICAgICAgY2hhciB0ZW1wW10gPSBuZXcgY2hhcltsZW5FYWNoXTsKICAgICAgICAgICAgZm9yICggaW50IGogPSAwOyBqIDwgbGVuRWFjaDsgaisrKXsKICAgICAgICAgICAgICAgIHRlbXBbal0gPSAoY2hhcikocmFuZG9tLm5leHRJbnQoMjYpICsgOTcpOwogICAgICAgICAgICB9CiAgICAgICAgICAgIG91dHB1dFtpXSA9IG5ldyBTdHJpbmcodGVtcCk7CiAgICAgICAgfQoKICAgICAgICByZXR1cm4gb3V0cHV0OwogICAgfQp9