贝壳笔试题:
方法一,用动态规划 时间复杂度O(n^2)
话不多说上代码
public static int lengthOfLIS(int[] nums) {
int max = 1;
int length[] = new int [nums.length];
for (int i = 0; i <nums.length;i++){ //子序列的终点
length[i] = 1; //默认只有自己一个
for (int j = 0; j <i;j++) { //从头开始向终点找序列
if(nums[i]> nums[j]){
length[i]=Math.max(length[i],length[j]+1);
}
}
max = Math.max(max,length[i]);
}
return max;
}
状态转移方程 dp[i] = max(dp[i] + dp[j]+1) (a[i>a[j]] 0<j<i)
dp[i] 表示长度数组
测试数据 N =8
数据为{5,1,6,8,2,4,5,10}
dp[i] | j=0 | j=1 | j=2 | j=3 | j=4 | j=5 | j=6 | j=7 |
dp[0] | 1 | |||||||
dp[1] | 1 | |||||||
dp[2] | 2 | 2 | ||||||
dp[3] | 2 | 2 | 3 | |||||
dp[4] | 1 | 2 | 2 | 2 | ||||
dp[5] | 1 | 2 | 2 | 2 | 3 | |||
dp[6] | 1 | 2 | 1 | 1 | 3 | 4 |
dp[7] | 2 | 2 | 3 | 4 | 4 | 4 | 4 | 5 |
整个dp[]数组大概就是dp[1,1,2,3,2,3,4,5]; 然后在取出最大的数字就行。
方法二: 贪心+二分 时间复杂度 O(NlogN)
只需要维护 dp[]数组,贪心的选择就是每次找最小的一个为最后一个,对于一个上升子序列如果最后一个数最小,越有利于继续往后再添加数字。 dp[] 最长长度的一个子序列,他的长度就是最长子序列长度。
还是以上的测试用例 arr{5,1,6,8,2,4,5,10}
//二分查
public static int lengthOfLIS(int[] nums){
int[] top = new int[nums.length];
int piles = 0;
for (int i = 0; i < nums.length; i++) {
int poker = nums[i];
*//***** 搜索左侧边界的二分查找 *****//*
int left = 0, right = piles;
while (left < right){
int mid = (left + right) / 2;
if (top[mid] > poker) {
right = mid;
} else if (top[mid] < poker) {
left = mid + 1;
} else {
right = mid;
}
}
if (left == piles) piles++;
top[left] = poker;
}
return piles;
}