leetcode-300

90 阅读1分钟

题目描述:具体描述见原题。简单来说就是求最长上升子序列长度。

解题思路:该题存在两种解题思路。第一种是直接考虑dp,dp[i]代表以nums[i]为结尾的字长上升子序列长度,则可得状态转移方程为dp[i] = max(dp[j] + 1)。其中j < i。因为两层循环所以时间复杂度为O(n2)(n²)。第二种思路是我抄来的,用一个数组,记录上升子序列最末尾的数字,如果该数字越小,那么后续该子序列增长的概率越大,此种思路更新策略为如果当前处理数字大于所有数组中元素,那么就直接放在末尾,如果当前数字大于[i-1]且小于[i],则更新数组[i]的值,最终该数组长度记为最长上升子序列长度,该方法时间复杂度为O(nlogn)(nlogn)。具体过程见代码。

具体代码:

// 直接dp
func lengthOfLIS(nums []int) int {
  if len(nums) == 0 {
		return 0
	}  
  dp, res := make([]int, len(nums)), 0
  	for i, _ := range dp{
		dp[i] = 1
	}
	for i := 0; i < len(nums); i++ {
		for j := 0; j < i; j++ {
			if nums[j] >= nums[i] {
				continue
			}
			if dp[i] < dp[j] + 1 {
				dp[i] = dp[j] + 1
			}
		}
		if res < dp[i] {
			res = dp[i]
		}
	}
	return res
}


// 使用数组记录

func lengthOfLIS(nums []int) int {
   dp := []int{}
   for _, num := range nums {
      i := sort.SearchInts(dp, num)
      if i == len(dp) {
         dp = append(dp, num)
      } else {
         dp[i] = num
      }
   }
   return len(dp)
}


补充说明: 两种解法在解题时间上还是有明显差距的。解法二真是好用,不知道是谁最先想出来的。