题目
Given an unsorted array of integers, find the length of longest increasing subsequence.
For example,
Given [10, 9, 2, 5, 3, 7, 101, 18]
,
The longest increasing subsequence is [2, 3, 7, 101]
, therefore the length is 4
. Note that there may be more than one LIS combination, it is only necessary for you to return the length.
Your algorithm should run in O(n2) complexity.
Follow up: Could you improve it to O(n log n) time complexity?
首先是O(n2)的方法,利于动态规划
模拟过程如下:
input[]: 10 9 2 5 3 7 101 18
store[]: 1 1 1 2 2 3 4 4
public int lengthOfLIS(int[] nums) {
if(nums==null || nums.length==0)
return 0;
int len = nums.length;
int[] store = new int[len];
for(int i=0;i<len;i++){
store[i] = 1;
for(int j = 0; j < i ;j++){
if(nums[j]<nums[i]){
store[i] = Math.max(store[i], store[j]+1);
}
}
}
int result = 1;
for(int i=0;i<store.length;i++)
result = Math.max(result, store[i]);
return result;
}
接下来扩展一下,把最长序列输出出来(可能多种,我只输出一个),思路是设定一个阈值(max=1),只要store[]中超过阈值的项写入列表List中,更新max,最后将max=1且比List[0]小的插入至List[0],长度加一,代码如下;
public List OutputOfLIS(int[] nums) {
int max = 1; //判断当前最大;
List<Integer> result_list = new ArrayList<Integer>();
if(nums==null || nums.length==0)
return null;
int len = nums.length;
int[] store = new int[len];
for(int i=0;i<len;i++){
store[i] = 1;
for(int j = 0; j < i ;j++){
if(nums[j]<nums[i]){
if(store[i]<store[j]+1&&store[j]+1>max){
max = store[j]+1;
store[i] = store[j]+1;
if(!result_list.contains(nums[i]))
result_list.add(nums[i]);
}
}
}
}
if(result_list.size()>0){
//把第一个补全
for(int i=0;i<len;i++){
if(nums[i]<result_list.get(0)){
result_list.add(0, nums[i]);
return result_list;
}
}
}else return result_list;
return result_list;
}
}
其次是O(nlogn)的方法,用的是栈和折半查找
思路部分参考http://blog.csdn.net/yorkcai/article/details/8651895
开一个栈,将nums[0]入栈,每次取栈顶元素top和读到的元素nums[i](1<i<n)做比较,如果nums[i]> top 则将nums[i]入栈;如果nums[i]<= top则二分查找栈中的比nums[i]大的第1个数,并用nums[i]替换它。 最长序列长度即为栈的大小top。
input[]: 10 9 2 5 3 7 101 18
栈的构造过程
10
9
2
2 5
2 3
2 3 7
2 3 7 101
2 3 7 18
2
2 5
2 3
2 3 7
2 3 7 101
2 3 7 18
代码如下
public int lengthOfLIS(int[] nums) {
if(nums==null||nums.length==0)
return 0;
int[] stack = new int[nums.length]; //模拟一个栈 result代表栈的深度
stack[0] = nums[0];
for(int i=1;i<nums.length;i++)
stack[i] = Integer.MAX_VALUE; //赋值成为nums[0],MAX_VALUE,MAX_VALUE......
int result = 0;
for(int i=1;i<nums.length;i++){
if(nums[i]>stack[result]){ //当前元素比栈顶还大
result ++;
stack[result] = nums[i];
//System.out.print("!!!:"+result+","+" ");
}
else if(nums[i]<stack[result]){
int mid = Arrays.binarySearch(stack, 0, result+1, nums[i]);
//System.out.print("!!!:"+result+","+mid+" ");
if(mid<0)
stack[-mid -1] = nums[i];
}
// for(int s=0;s<=result;s++)
// System.out.print(stack[s]+" ");
// System.out.println();
}
return result+1;
值得注意的,O(nlogn)
input[]: 10 9 2 5 3 7 101 6
栈的构造过程
10
9
2
2 5
2 3
2 3 7
2 3 7 101
2 3 6 101 //这一次替换了最长序列,与预期最长序列不同,但是长度却相同
2
2 5
2 3
2 3 7
2 3 7 101
2 3 6 101 //这一次替换了最长序列,与预期最长序列不同,但是长度却相同
分析:
当nums[i]>top时,top+1,与预期相同;
当nums[i]<top时, 这时num[i]会替换栈里面的某一个元素,top大小不变,但是序列发生了变化;
如果只求个数的话,这个算法比较高效;但如果要求打印出序列时,就只能用动态规划的方法。