【1】题目: 给定一个无序数组,找到最长的单调自增子序列(不一定连续,但是顺序不能乱)的长度;
【2】看个荔枝:给定数组 [10, 9, 2, 5, 3, 7, 101, 18] 输出结果为 [2, 3, 7, 101]。。算法时间复杂度一般为 O(n^2) 也可以优化到 O(nlgn);
【3】算法思路:对无序数组做一次遍历 并找出最小最大值v1, v2及其下标i1, i2;下一次循环遍历的范围是在 [i1+1, i2-1] 这个范围内找出 最小最大值 及其下标,每次循环 counter += 2...... 算法结束标志是 i1 小于i2;且当 i1等于i2时 表明 单调自增子序列的长度是奇数,所以counter++;算法实现如下:下面算法的时间复杂度是 O(n^2);
// input: [10, 9, 2, 5, 3, 7, 101, 18]
// output: [2, 3, 7, 101]
public class NiBiNuCycle {
static int counter = 0;
public static void main(String[] args) {
// int[] array = {10, 9, 2, 5, 3, 7, 101, 18};
int[] array = {10, 90, 76, 12, 25, 36, 78, 99, 177, 132, 156};
find(array, 0, array.length-1);
System.out.println("result = " + counter);
}
static void find(int[] array, int i1, int i2) {
int ci1=0, ci2=0;
// ci1, ci2 是 i1 和 i2 的 copy
// v1 v2 作为在范围 [i1, i2] 区域中的最小最大值.
//
while(i1<i2) {
int v1 = Integer.MAX_VALUE, v2 = Integer.MIN_VALUE;
ci1=i1; ci2=i2;
for (int i = i1; i <= i2; i++) {
if(array[i] > v2) {
v2 = array[i];
ci2 = i;
}
if(array[i] < v1) {
v1 = array[i];
ci1 = i;
}
}
System.out.println("v1 = " + v1 + ", v2 = " + v2);
i1 = ci1+1;
i2 = ci2-1;
counter += 2;
}
if(i1==i2) {
counter++;
}
}
}
【4】O(nlgn)的时间复杂度的思路是:利用分治思想,下面给出伪代码,但源码未实现,仅供参考;
// input: [10, 9, 2, 5, 3, 7, 101, 18]
// output: [2, 3, 7, 101]
// 此题的分治版本.(伪代码,源码未实现)
class MinMax {
int i1; // 最小值的对应index
int i2; // 最大值的......
public MinMax(int i1, int i2) {
this.i1 = i1;
this.i2 = i2;
}
public MinMax(){}
}
public class NiBiNuRecursion {
static int counter = 0;
static MinMax result;
public static void main(String[] args) {
int[] array = {10, 90, 76, 12, 25, 78, 99, 177, 132, 156};
find(array, 0, array.length-1);
System.out.println("result = " + counter);
}
// 分治算法.
static MinMax find(int[] array, int i1, int i2) {
if(i1<i2) {
int center = (i1+i2)/2;
MinMax a = find(array, i1, center);
MinMax b = find(array, center+1, i2);
merge(...); // 这里应该要做一次merge.
}
else
return new MinMax(i1,i1);
return result;
}
}