题目:
给定一个无序的整数数组,找到其中最长上升子序列的长度。
示例:
输入: [10,9,2,5,3,7,101,18]
输出: 4
解释: 最长的上升子序列是 [2,3,7,101],它的长度是 4。
说明:
可能会有多种最长上升子序列的组合,你只需要输出对应的长度即可。
你算法的时间复杂度应该为 O(n2) 。
进阶: 你能将算法的时间复杂度降低到 O(n log n) 吗?
思路:这个题是使用动态规划.数组dp[n]用来表示以第n个数组元素结尾的最长的递增子序列的长度。递推公式是dp[n]=max(dp[i]+1,1).其中需要遍历所有下标小于n 的数组元素。这种思路的时间复杂度是O(n^2)。
这个题我刚开始就想简单了,以为只比较它的前一个就行,实际上需要比较下标比n小的所有的元素。
我自己又做了一遍这个题,结果还是不对。。。。应该直接用动态规划做。
除此之外还可以使用二分法将复杂度降低到O(nlogn).代码如代码1.数组tail[n]表示长度为n+1的最长子序列最后的一个数字。我自己写代码的时候,把二分查找int mid = l + (h - l) / 2;中的l写成了1.。。。。。。
代码:
class Solution {
public int lengthOfLIS(int[] nums) {
if(nums==null||nums.length==0)
return 0;
if(nums.length==1)
return 1;
int n=nums.length;
int []dp=new int[n];
for(int i=0;i<n;i++){
int max=1;
for(int j=0;j<i;j++){
if(nums[i]>nums[j]){
max=Math.max(dp[j]+1,max);
}
}
dp[i]=max;//刚开始的时候我把这个写在j的循环里面了
}
int tem=0;
for(int i=0;i<n;i++){
tem=Math.max(tem,dp[i]);
}
return tem;
}
}
代码1:
class Solution {
public int lengthOfLIS(int[] nums) {
int n = nums.length;
int[] tails = new int[n];
int len = 0;
for (int num : nums) {
int index = binarySearch(tails, len, num);
tails[index] = num;
if (index == len) {
len++;
}
}
return len;
}
//这个好像是使用二分法将新的num插入到tails数组中
private int binarySearch(int[] tails, int len, int key) {
int l = 0, h = len;
while (l < h) {
int mid = l + (h - l) / 2;
if (tails[mid] == key) {
return mid;
} else if (tails[mid] > key) {
h = mid;
} else {
l = mid + 1;
}
}
return l;
}
}
这个里面还是是不会有相同的数,顺丰的笔试题有一个是可能有相同的数,把牛课上大神的代码写在这里:
import java.util.Scanner;
public class sf2 {
//这是一个静态内部类。有一个数值一个索引
private static class Point implements Comparable {
int num;
int index;
Point(int num, int index) {
this.num = num;
this.index = index;
}
//内部实现compare方法。这个方法是用来处理相同的数字的。数字相同,直接比较索引。
public int compareTo(Object o) {
Point p = (Point) o;
if (p.num == this.num) {
return this.index - p.index;
}
return this.num - p.num;
}
}
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
int n = scanner.nextInt();
Point[] points = new Point[n];
for (int i = 0; i < n; i++) {
int num = scanner.nextInt();
points[i] = new Point(num, i);
}
System.out.print(maxLengthOfRisingSubArray(points));
}
private static int maxLengthOfRisingSubArray(Point[] nums) {
int n = nums.length;
Point[] array = new Point[n];
int index = 0;
for (int i = 0; i < n; i++) {
if (i == 0) {
array[index++] = nums[i];
} else {
int ceilIndex = ceil(array, index, nums[i]);
if (ceilIndex == index) {
array[index++] = nums[i];
} else if (array[ceilIndex].compareTo(nums[i]) > 0) {
array[ceilIndex] = nums[i];
}
}
}
return index;
}
//这个应该是用二分法实现的
private static int ceil(Point[] array, int index, Point target) {
int left = 0, right = index;
while (left < right) {
int mid = left + ((right - left) >> 1);
if (array[mid].compareTo(target) <= 0) {
left = mid + 1;
} else {
right = mid;
}
}
if (left - 1 >= 0 && array[left - 1].compareTo(target) == 0) {
return left - 1;
}
return left;
}
}
本文探讨了寻找无序整数数组中最长上升子序列的问题,通过动态规划和二分法实现,前者时间复杂度为O(n^2),后者优化至O(nlogn)。文章提供了详细的算法思路和代码示例。
1021

被折叠的 条评论
为什么被折叠?



