最长递增子序列题目的思路探讨与源码
最长递增子序列的题目如下图,该题属于动态规划和二分查找类型的题目,主要考察对于动态规划和二分查找法的使用和理解。本文的题目作者想到2种方法,分别是动态规划方法和二分查找法,其中动态规划方法使用java进行编写,而二分查找法使用Python进行编写,当然这可能不是最优的解法,还希望各位大佬给出更快的算法。
本人认为该题目可以使用动态规划方法,首先计算数组的长度,并且判断是否为空,如果长度是0就直接返回0并且结束程序。然后开始进行动态规划的数组初始化,遍历原始数组nums,第一个下标是从0到数组下标的,第二个下标是从0到第一个下标的,动态规划内部的核心思路是,当前的动态数组的值是取决于max{dp[i],dp[j]+1}更大值,当每次内部循环结束的时候,都要把最终的最长递增子序列长度进行更新。那么按照这个思路我们的Java代码如下:
#喷火龙与水箭龟
class Solution {
public int lengthOfLIS(int[] nums) {
int lenNum=nums.length;
if(lenNum==0){
return 0;
}
int finalNum=0;
int[] dynamicArray = new int[lenNum];
Arrays.fill(dynamicArray,1);
for(int jr=0;jr<nums.length;jr++){
for(int kv=0;kv<jr;kv++){
if(nums[kv]<nums[jr]){
dynamicArray[jr]=Math.max(dynamicArray[kv]+1,dynamicArray[jr]);
}
}
finalNum=Math.max(dynamicArray[jr],finalNum);
}
return finalNum;
}
}
显然,我们还可以使用二分查找的方法进行处理,首先进行长度计算和初始化赋值,将一个历史数组全部初始化为0的元素,然后开始遍历,每次计算下标的中间值,如果历史数组的值比当前元素值小,则左边的下标更新为中间值下标加1,否则右边的下标更新为中间值,并且在循环的末尾对右侧的下标进行判断,如果和最终的返回值一样则会将最终的返回值加1,最后返回结果即可。所以根据这个思路就可以写出代码,下面是Python代码部分:
#喷火龙与水箭龟
class Solution:
def lengthOfLIS(self, nums: [int]) -> int:
lenNum=len(nums)
endNum=lenNum*[0]
finalNum=0
for np in nums:
iv=0
jv=finalNum
while(iv<jv):
midNum=(iv+jv)//2
if(endNum[midNum]<np):
iv=midNum+1
else:
jv=midNum
endNum[iv]=np
if(jv==finalNum):
finalNum=finalNum+1
return finalNum
从结果来说java版本的动态规划法的速度比较一般,但是python版本的二分查找方法的速度还不错,但应该是有更多的方法可以进一步提速的,希望朋友们能够多多指教,非常感谢。