一共包括三个子问题
实现语言问golang,在二分法中用到了sort包里的SearchInts
最长连续递增子序列
func continuouslengthOfLIS(nums []int) int {
//最长的连续递增子序列长度
ans, left := 1, 0
for i := 1; i < len(nums); i++ {
if nums[i] <= nums[i-1] {
ans = max(ans, i-left)
left = i
}
}
ans = max(ans, len(nums)-left)
return ans
}
最长递增子序列的长度
时间复杂度为n²
func dplengthOfLIS(nums []int) int {
//返回最长递增子序列的长度
ans := 0
n := len(nums)
dp := make([]int, n)
//dp[i]表示前i个数组成的最长子序列长度
for i := 0; i < n; i++ {
//子序列长度最少为1
dp[i] = 1
for j := 0; j < i; j++ {
if nums[i] > nums[j] {
//如果i大于j对应的数,那么第j个数对应的最长子序列就可以加上第i个数,长度+1
dp[i] = max(dp[i], dp[j]+1)
//记录最大的dp值
ans = max(ans, dp[i])
}
}
}
return ans
}
使用二分法
时间复杂度为n * log(n)
func binarysearchlengthOfLIS(nums []int) int {
//采用二分法和贪心策略
//基本思想就是尽量让数组的尾部小,这样就可以添进来更多数
//例如1 100 2 10 20 3 4 30 170 150
//1
//1 100
//1 2
//1 2 10
//1 2 10 20
//1 2 3 20
//1 2 3 4
//1 2 3 4 30
//1 2 3 4 30 170
//1 2 3 4 30 150
ans := []int{}
ans = append(ans, nums[0])
for i := 1; i < len(nums); i++ {
//遍历nums数组
if nums[i] > ans[len(ans)-1] {
//如果第i个数比ans数组的末尾元素大,就添加进去
ans = append(ans, nums[i])
} else if nums[i] < ans[len(ans)-1] {
//如果第i个数比ans数组的末尾元素小,就一直往前寻找,直到找到第一个比他大的数,替换掉
index := sort.SearchInts(ans, nums[i])
ans[index] = nums[i]
}
}
return len(ans)
}
最长递增子序列的个数
func numOflengthOfLIS(nums []int) int {
//返回最长子序列对应的个数
ans := 1
// ans记录最长的长度
n := len(nums)
//dp 记录前i个数的最长子序列的长度
dp := make([]int, n)
//count 记录前i个数的最长子序列长度的个数
count := make([]int, n)
//dp[i]表示前i个数组成的最长子序列长度
for i := 0; i < n; i++ {
//子序列长度最少为1
dp[i] = 1
count[i] = 1
for j := 0; j < i; j++ {
if nums[i] > nums[j] {
//如果i大于j对应的数,那么第j个数对应的最长子序列就可以加上第i个数,长度+1
if dp[j]+1 > dp[i] {
//如果前j个数的最长子序列长度+1比当前前i个数的最长子序列长度长,那就更新当前的长度,且排列方式数量等于前j个的排列方式
dp[i] = dp[j] + 1
count[i] = count[j]
} else if dp[j]+1 == dp[i] {
//如果前j个数的最长子序列长度+1和当前前i个数的最长子序列长度一样,那这个长度的方式就再加上前j个的排列方式
count[i] += count[j]
}
//还有另一种情况就是前j个的长度+1,还没有现在的长,那就抛弃不用
//记录最大的dp值
ans = max(ans, dp[i])
}
}
}
if ans == 1 {
return n
}
ret := 0
for i := range dp {
if dp[i] == ans {
ret += count[i]
}
}
return ret
}