github.com/qiuhoude/go-web@v0.0.0-20220223060959-ab545e78f20d/algorithm/leetcode/longest-increasing-subsequence_test.go (about)

     1  package leetcode
     2  
     3  import "testing"
     4  
     5  //leetcode 300. 最长上升子序列
     6  // https://leetcode-cn.com/problems/longest-increasing-subsequence
     7  
     8  /*
     9  给定一个无序的整数数组,找到其中最长上升子序列的长度。
    10  输入: [10,9,2,5,3,7,101,18]
    11  输出: 4
    12  解释: 最长的上升子序列是 [2,3,7,101],它的长度是 4。
    13  */
    14  
    15  // 思路: 求出 f(i) = j i表示数值的下表,j表示长度
    16  // 当下表为i 时 前面序列的长度
    17  // f(0) = 1 10前面没有比他小的
    18  // f(1) = 1 9 前面没有比他小的
    19  // f(2) = f(1)+1 = 2
    20  // f(3) = max(f(0),f(1))+1
    21  // db[] 保存的就是 下表为i的时最长子序列长度
    22  
    23  func lengthOfLIS(nums []int) int {
    24  	dp := make([]int, len(nums))
    25  	max := 0
    26  	for i := 0; i < len(nums); i++ {
    27  		dp[i] = 1
    28  		//比较前面i项最大子序列值
    29  		for j := 0; j < i; j++ {
    30  			if nums[j] < nums[i] && dp[i] < dp[j]+1 {
    31  				dp[i] = dp[j] + 1
    32  			}
    33  		}
    34  		if dp[i] > max {
    35  			max = dp[i]
    36  		}
    37  	}
    38  	return max
    39  }
    40  
    41  func lengthOfLIS2(nums []int) int {
    42  	if len(nums) == 0 {
    43  		return 0
    44  	}
    45  	// tail 数组的定义:长度为 i + 1 的上升子序列的末尾最小是几
    46  	tail := make([]int, len(nums))
    47  	// 遍历第 1 个数,直接放在有序数组 tail 的开头
    48  	tail[0] = nums[0]
    49  	// end 表示有序数组 tail 的最后一个已经赋值元素的索引
    50  	end := 0
    51  	for i := 1; i < len(nums); i++ {
    52  		// 【逻辑 1】比 tail 数组实际有效的末尾的那个元素还大
    53  		if nums[i] > tail[end] {
    54  			end++
    55  			tail[end] = nums[i]
    56  		} else {
    57  			// 使用二分查找法,在有序数组 tail 中
    58  			// 找到第 1 个大于等于 nums[i] 的元素,尝试让那个元素更小
    59  			left := 0
    60  			right := left
    61  			for left < right {
    62  				// 选左中位数不是偶然,而是有原因的,原因请见 LeetCode 第 35 题题解
    63  				mid := left + (right-left)/2
    64  				if tail[mid] < nums[i] {
    65  					// 中位数肯定不是要找的数,把它写在分支的前面
    66  					left = mid + 1
    67  				} else {
    68  					right = mid
    69  				}
    70  			}
    71  			//走到这里是因为 【逻辑 1】 的反面,因此一定能找到第 1 个大于等于 nums[i] 的元素
    72  			tail[left] = nums[i]
    73  		}
    74  	}
    75  	end++
    76  	return end
    77  }
    78  
    79  func TestLengthOfLIS(t *testing.T) {
    80  	tests := []struct {
    81  		name string
    82  		args []int
    83  		want int
    84  	}{
    85  		{"[10,9,2,5,3,7,101,18] => 4", []int{10, 9, 2, 5, 3, 7, 101, 18}, 4},
    86  		{"[10,9,2,5,3,4] => 3", []int{10, 9, 2, 5, 3, 4}, 3},
    87  	}
    88  	for _, tt := range tests {
    89  		t.Run(tt.name, func(t *testing.T) {
    90  			if got := lengthOfLIS(tt.args); got != tt.want {
    91  				t.Errorf("lengthOfLIS() = %v, want %v", got, tt.want)
    92  
    93  			}
    94  		})
    95  	}
    96  }