leetcode热题100-Go解-2025.4.10 90/100
终于要入门了
笔试记录等维护明天再做吧
累了
4.寻找两个正序数组的中位数 给定两个大小分别为 m
和 n
的正序(从小到大)数组 nums1
和 nums2
。请你找出并返回这两个正序数组的 中位数 。
算法的时间复杂度应该为 O(log (m+n))
。
示例 1:
1 2 3 输入:nums1 = [1,3], nums2 = [2] 输出:2.00000 解释:合并数组 = [1,2,3] ,中位数 2
示例 2:
1 2 3 输入:nums1 = [1,2], nums2 = [3,4] 输出:2.50000 解释:合并数组 = [1,2,3,4] ,中位数 (2 + 3) / 2 = 2.5
解一 O(log(m+n)) 思路
官方题解 等同于找到第k
小的元素,k = (m + n + 1) / 2
逐步排除小数直到排除了k个后自然得到
解二 更优解 O(log(min(m, n)))
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 func findMedianSortedArrays (nums1 []int , nums2 []int ) float64 { m, n := len (nums1), len (nums2) if m > n { nums1, nums2 = nums2, nums1 m, n = n, m } left, right := 0 , m for left <= right { i := (left + right) / 2 j := (m+n+1 )/2 - i nums1LeftMax := math.MinInt32 if i > 0 { nums1LeftMax = nums1[i-1 ] } nums2LeftMax := math.MinInt32 if j > 0 { nums2LeftMax = nums2[j-1 ] } nums1RightMin := math.MaxInt32 if i < m { nums1RightMin = nums1[i] } nums2RightMin := math.MaxInt32 if j < n { nums2RightMin = nums2[j] } if nums1LeftMax <= nums2RightMin && nums2LeftMax <= nums1RightMin { if (m+n)%2 == 0 { return float64 (max(nums1LeftMax, nums2LeftMax)+min(nums1RightMin, nums2RightMin)) / 2 } else { return float64 (max(nums1LeftMax, nums2LeftMax)) } } else if nums1LeftMax > nums2RightMin { right = i - 1 } else { left = i + 1 } } return 0.0 }
20. 有效的括号 水题
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 func isValid (s string ) bool { stack := []rune {} for _, c := range s { if c == '(' || c == '[' || c == '{' { stack = append (stack, c) } else if c == ')' { if len (stack) == 0 || stack[len (stack)-1 ] != '(' { return false } else { stack = stack[:len (stack)-1 ] } } else if c == ']' { if len (stack) == 0 || stack[len (stack)-1 ] != '[' { return false } else { stack = stack[:len (stack)-1 ] } } else if c == '}' { if len (stack) == 0 || stack[len (stack)-1 ] != '{' { return false } else { stack = stack[:len (stack)-1 ] } } else { return false } } if len (stack) == 0 { return true } else { return false } }
155.最小栈 设计一个支持 push
,pop
,top
操作,并能在常数时间内检索到最小元素的栈。
实现 MinStack
类:
MinStack()
初始化堆栈对象。
void push(int val)
将元素val推入堆栈。
void pop()
删除堆栈顶部的元素。
int top()
获取堆栈顶部的元素。
int getMin()
获取堆栈中的最小元素。
示例 1:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 输入: ["MinStack","push","push","push","getMin","pop","top","getMin"] [[],[-2],[0],[-3],[],[],[],[]] 输出: [null,null,null,null,-3,null,0,-2] 解释: MinStack minStack = new MinStack(); minStack.push(-2); minStack.push(0); minStack.push(-3); minStack.getMin(); --> 返回 -3. minStack.pop(); minStack.top(); --> 返回 0. minStack.getMin(); --> 返回 -2.
思路:
实际上是维护两个栈,一个数据栈,一个最小值栈
数据出栈时判断是否为最小值,是则最小值栈同步更新
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 type MinStack struct { stack []int minStack []int } func Constructor () MinStack { return MinStack{ stack: []int {}, minStack: []int {}, } } func (this *MinStack) Push(val int ) { this.stack = append (this.stack, val) if len (this.minStack) == 0 || val <= this.minStack[len (this.minStack)-1 ] { this.minStack = append (this.minStack, val) } } func (this *MinStack) Pop() { if len (this.stack) == 0 { return } if this.stack[len (this.stack)-1 ] == this.minStack[len (this.minStack)-1 ] { this.minStack = this.minStack[:len (this.minStack)-1 ] } this.stack = this.stack[:len (this.stack)-1 ] } func (this *MinStack) Top() int { if len (this.stack) == 0 { return 0 } return this.stack[len (this.stack)-1 ] } func (this *MinStack) GetMin() int { if len (this.minStack) == 0 { return 0 } return this.minStack[len (this.minStack)-1 ] }
394.字符串解码 水题 类似的还有逆波兰表达式
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 func decodeString (s string ) string { stack := []byte {} for i := 0 ; i < len (s); i++ { if s[i] != ']' { stack = append (stack, s[i]) } else { str := []byte {} for len (stack) > 0 && stack[len (stack)-1 ] != '[' { str = append (str, stack[len (stack)-1 ]) stack = stack[:len (stack)-1 ] } stack = stack[:len (stack)-1 ] num := 0 base := 1 for len (stack) > 0 && stack[len (stack)-1 ] >= '0' && stack[len (stack)-1 ] <= '9' { num += int (stack[len (stack)-1 ]-'0' ) * base stack = stack[:len (stack)-1 ] base *= 10 } for j := 0 ; j < num; j++ { for k := len (str) - 1 ; k >= 0 ; k-- { stack = append (stack, str[k]) } } } } return string (stack) }
84.柱状图中最大的矩形 给定 n 个非负整数,用来表示柱状图中各个柱子的高度。每个柱子彼此相邻,且宽度为 1 。
求在该柱状图中,能够勾勒出来的矩形的最大面积。
示例 1:
1 2 3 输入:heights = [2,1,5,6,2,3] 输出:10 解释:最大的矩形为图中红色区域,面积为 10
示例 2:
1 2 输入: heights = [2,4] 输出: 4
解法 单调栈 一轮遍历解决
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 func largestRectangleArea (heights []int ) int { heights = append ([]int {0 }, heights...) heights = append (heights, 0 ) stack := []int {} maxArea := 0 for i := 0 ; i < len (heights); i++ { for len (stack) > 0 && heights[i] < heights[stack[len (stack)-1 ]] { top := stack[len (stack)-1 ] stack = stack[:len (stack)-1 ] area := heights[top] * (i - stack[len (stack)-1 ] - 1 ) if area > maxArea { maxArea = area } } stack = append (stack, i) } return maxArea }
215.数组中的第K个最大元素 给定整数数组 nums
和整数 k
,请返回数组中第 **k**
个最大的元素。
请注意,你需要找的是数组排序后的第 k
个最大的元素,而不是第 k
个不同的元素。
你必须设计并实现时间复杂度为 O(n)
的算法解决此问题。
解一 堆排 O(nlogn)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 func heapify (heap []int , i int ) { left := 2 *i + 1 right := 2 *i + 2 largest := i if left < len (heap) && heap[left] > heap[largest] { largest = left } if right < len (heap) && heap[right] > heap[largest] { largest = right } if largest != i { heap[i], heap[largest] = heap[largest], heap[i] heapify(heap, largest) } } func findKthLargest (nums []int , k int ) int { heap := make ([]int , len (nums)) for i := 0 ; i < len (nums); i++ { heap[i] = nums[i] } for i := len (heap)/2 - 1 ; i >= 0 ; i-- { heapify(heap, i) } for i := 0 ; i < k-1 ; i++ { heap[0 ] = heap[len (heap)-1 ] heap = heap[:len (heap)-1 ] heapify(heap, 0 ) } return heap[0 ] }
解二 快排变式,快速选择
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 func findKthLargest (nums []int , k int ) int { n := len (nums) return quickSelect(nums, 0 , n-1 , n-k) } func quickSelect (nums []int , l, r, k int ) int { if l == r { return nums[k] } pivot := nums[(l+r)/2 ] i, j := l, r for i <= j { for nums[i] < pivot { i++ } for nums[j] > pivot { j-- } if i <= j { nums[i], nums[j] = nums[j], nums[i] i++ j-- } } if k <= j { return quickSelect(nums, l, j, k) } if k >= i { return quickSelect(nums, i, r, k) } return nums[k] }
347.前 K 个高频元素 给你一个整数数组 nums
和一个整数 k
,请你返回其中出现频率前 k
高的元素。你可以按 任意顺序 返回答案。
示例 1:
1 2 输入: nums = [1,1,1,2,2,3], k = 2 输出: [1,2]
示例 2:
1 2 输入: nums = [1], k = 1 输出: [1]
解法 小顶堆
先遍历建立 值-频率 HashMap
再变量Map建立k容量小顶堆,达到上限时优先移除堆顶元素
最后剩下k容量即为前k高频的元素
小顶堆的实现:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 type Item struct { Val int Count int } type PriorityQueue []*Itemfunc (pq PriorityQueue) Len() int { return len (pq) }func (pq PriorityQueue) Less(i, j int ) bool { return pq[i].Count < pq[j].Count }func (pq PriorityQueue) Swap(i, j int ) { pq[i], pq[j] = pq[j], pq[i] }func (pq *PriorityQueue) Push(x interface {}) { item := x.(*Item) *pq = append (*pq, item) } func (pq *PriorityQueue) Pop() interface {} { old := *pq n := len (old) item := old[n-1 ] *pq = old[0 : n-1 ] return item }
具体方法:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 func topKFrequent (nums []int , k int ) []int { frequency := make (map [int ]int ) for _, num := range nums { frequency[num]++ } pq := make (PriorityQueue, 0 ) heap.Init(&pq) for value, count := range frequency { heap.Push(&pq, &Item{value, count}) if pq.Len() > k { heap.Pop(&pq) } } result := make ([]int , k) for i := k - 1 ; i >= 0 ; i-- { result[i] = heap.Pop(&pq).(*Item).Val } return result }
295.数据流的中位数 中位数 是有序整数列表中的中间值。如果列表的大小是偶数,则没有中间值,中位数是两个中间值的平均值。
例如 arr = [2,3,4]
的中位数是 3
。
例如 arr = [2,3]
的中位数是 (2 + 3) / 2 = 2.5
。
实现 MedianFinder 类:
MedianFinder()
初始化 MedianFinder
对象。
void addNum(int num)
将数据流中的整数 num
添加到数据结构中。
double findMedian()
返回到目前为止所有元素的中位数。与实际答案相差 10-5
以内的答案将被接受。
示例 1:
1 2 3 4 5 6 7 8 9 10 11 12 13 输入 ["MedianFinder", "addNum", "addNum", "findMedian", "addNum", "findMedian"] [[], [1], [2], [], [3], []] 输出 [null, null, null, 1.5, null, 2.0] 解释 MedianFinder medianFinder = new MedianFinder(); medianFinder.addNum(1); // arr = [1] medianFinder.addNum(2); // arr = [1, 2] medianFinder.findMedian(); // 返回 1.5 ((1 + 2) / 2) medianFinder.addNum(3); // arr[1, 2, 3] medianFinder.findMedian(); // return 2.0
解法:
采用两个小顶堆,
对于大于当前中位数的值,我们直接存储,便于直接调出最小值
对于小于当前中位数的值,我们做负值存储,便于直接调出最大值
小顶堆:
1 2 3 4 5 6 7 8 9 10 11 12 13 type PriorityQueue2 struct { sort.IntSlice } func (pq *PriorityQueue2) Push(v interface {}) { pq.IntSlice = append (pq.IntSlice, v.(int )) } func (pq *PriorityQueue2) Pop() interface {} { a := pq.IntSlice v := a[len (a)-1 ] pq.IntSlice = a[:len (a)-1 ] return v }
题解:
注意负值的处理
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 type MedianFinder struct { minHeap *PriorityQueue2 maxHeap *PriorityQueue2 } func Constructor2 () MedianFinder { return MedianFinder{ minHeap: &PriorityQueue2{}, maxHeap: &PriorityQueue2{}, } } func (this *MedianFinder) AddNum(num int ) { minh, maxh := this.minHeap, this.maxHeap if minh.Len() == 0 || num <= -minh.IntSlice[0 ] { heap.Push(minh, -num) if minh.Len() > maxh.Len()+1 { heap.Push(maxh, -heap.Pop(minh).(int )) } } else { heap.Push(maxh, num) if maxh.Len() > minh.Len() { heap.Push(minh, -heap.Pop(maxh).(int )) } } } func (this *MedianFinder) FindMedian() float64 { if this.minHeap.Len() > this.maxHeap.Len() { return float64 (-this.minHeap.IntSlice[0 ]) } return float64 (this.maxHeap.IntSlice[0 ]-this.minHeap.IntSlice[0 ]) / 2 }
121.买卖股票的最佳时机 给定一个数组 prices
,它的第 i
个元素 prices[i]
表示一支给定股票第 i
天的价格。
你只能选择 某一天 买入这只股票,并选择在 未来的某一个不同的日子 卖出该股票。设计一个算法来计算你所能获取的最大利润。
返回你可以从这笔交易中获取的最大利润。如果你不能获取任何利润,返回 0
。
示例 1:
1 2 3 4 输入:[7,1,5,3,6,4] 输出:5 解释:在第 2 天(股票价格 = 1)的时候买入,在第 5 天(股票价格 = 6)的时候卖出,最大利润 = 6-1 = 5 。 注意利润不能是 7-1 = 6, 因为卖出价格需要大于买入价格;同时,你不能在买入前卖出股票。
示例 2:
1 2 3 输入:prices = [7,6,4,3,1] 输出:0 解释:在这种情况下, 没有交易完成, 所以最大利润为 0。
贪心算法入门
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 func maxProfit (prices []int ) int { minPrice := prices[0 ] maxProfit := 0 for i := 1 ; i < len (prices); i++ { if prices[i] < minPrice { minPrice = prices[i] }else if prices[i] - minPrice > maxProfit { maxProfit = prices[i] - minPrice }else { continue } } return maxProfit }
55. 跳跃游戏 水题
1 2 3 4 5 6 7 8 9 10 11 12 func canJump (nums []int ) bool { maxPosition := 0 for i := 0 ; i < len (nums); i++ { if i <= maxPosition { maxPosition = max(maxPosition, i+nums[i]) if maxPosition >= len (nums)-1 { return true } } } return false }
45. 跳跃游戏 II 比上题稍微难点
解一 正向 O(n)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 func jump (nums []int ) int { end := 0 maxPosition := 0 steps := 0 for i := 0 ; i < len (nums)-1 ; i++ { maxPosition = max(maxPosition, i+nums[i]) if i == end { end = maxPosition steps++ } } return steps }
解二 反向 O(n^2)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 func jump2 (nums []int ) int { position := len (nums) - 1 steps := 0 for position > 0 { for i := 0 ; i < position; i++ { if i+nums[i] >= position { position = i steps++ break } } } return steps }
70.爬楼梯 假设你正在爬楼梯。需要 n
阶你才能到达楼顶。
每次你可以爬 1
或 2
个台阶。你有多少种不同的方法可以爬到楼顶呢?
示例 1:
1 2 3 4 5 输入:n = 2 输出:2 解释:有两种方法可以爬到楼顶。 1. 1 阶 + 1 阶 2. 2 阶
示例 2:
1 2 3 4 5 6 输入:n = 3 输出:3 解释:有三种方法可以爬到楼顶。 1. 1 阶 + 1 阶 + 1 阶 2. 1 阶 + 2 阶 3. 2 阶 + 1 阶
1 2 3 4 5 6 7 8 9 10 11 12 13 func climbStairs (n int ) int { if n == 1 { return 1 } dp := make ([]int , n+1 ) dp[1 ] = 1 dp[2 ] = 2 for i := 3 ; i <= n; i++ { dp[i] = dp[i-1 ] + dp[i-2 ] } return dp[n] }
118.杨辉三角 水题
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 func generate (numRows int ) [][]int { res := make ([][]int , numRows) for i := 0 ; i < numRows; i++ { res[i] = make ([]int , i+1 ) } for i := 0 ; i < numRows; i++ { for j := 0 ; j <= i; j++ { if j == 0 || j == i { res[i][j] = 1 } } } for i := 2 ; i < numRows; i++ { for j := 1 ; j < i; j++ { res[i][j] = res[i-1 ][j-1 ] + res[i-1 ][j] } } return res }
198.打家劫舍 你是一个专业的小偷,计划偷窃沿街的房屋。每间房内都藏有一定的现金,影响你偷窃的唯一制约因素就是相邻的房屋装有相互连通的防盗系统,如果两间相邻的房屋在同一晚上被小偷闯入,系统会自动报警 。
给定一个代表每个房屋存放金额的非负整数数组,计算你 不触动警报装置的情况下 ,一夜之内能够偷窃到的最高金额。
示例 1:
1 2 3 4 输入:[1,2,3,1] 输出:4 解释:偷窃 1 号房屋 (金额 = 1) ,然后偷窃 3 号房屋 (金额 = 3)。 偷窃到的最高金额 = 1 + 3 = 4 。
示例 2:
1 2 3 4 输入:[2,7,9,3,1] 输出:12 解释:偷窃 1 号房屋 (金额 = 2), 偷窃 3 号房屋 (金额 = 9),接着偷窃 5 号房屋 (金额 = 1)。 偷窃到的最高金额 = 2 + 9 + 1 = 12 。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 func rob (nums []int ) int { if len (nums) == 0 { return 0 } if len (nums) == 1 { return nums[0 ] } dp := make ([]int , len (nums)) dp[0 ] = nums[0 ] dp[1 ] = max(nums[0 ], nums[1 ]) for i := 2 ; i < len (nums); i++ { dp[i] = max(dp[i-1 ], dp[i-2 ]+nums[i]) } return dp[len (nums)-1 ] }
763.划分字母区间 给你一个字符串 s
。我们要把这个字符串划分为尽可能多的片段,同一字母最多出现在一个片段中。例如,字符串 "ababcc"
能够被分为 ["abab", "cc"]
,但类似 ["aba", "bcc"]
或 ["ab", "ab", "cc"]
的划分是非法的。
注意,划分结果需要满足:将所有划分结果按顺序连接,得到的字符串仍然是 s
。
返回一个表示每个字符串片段的长度的列表。
示例 1:
1 2 3 4 5 6 输入:s = "ababcbacadefegdehijhklij" 输出:[9,7,8] 解释: 划分结果为 "ababcbaca"、"defegde"、"hijhklij" 。 每个字母最多出现在一个片段中。 像 "ababcbacadefegde", "hijhklij" 这样的划分是错误的,因为划分的片段数较少。
示例 2:
1 2 输入:s = "eccbbbbdec" 输出:[10]
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 func partitionLabels (s string ) []int { lastPos := [26 ]int {} for i, c := range s { lastPos[c-'a' ] = i } start, end := 0 , 0 var partition []int for i, c := range s { if lastPos[c-'a' ] > end { end = lastPos[c-'a' ] } if i == end { partition = append (partition, end-start+1 ) start = end + 1 } } return partition }
279. 完全平方数 给你一个整数 n
,返回 和为 n
的完全平方数的最少数量 。
完全平方数 是一个整数,其值等于另一个整数的平方;换句话说,其值等于一个整数自乘的积。例如,1
、4
、9
和 16
都是完全平方数,而 3
和 11
不是。
示例 1:
1 2 3 输入:n = 12 输出:3 解释:12 = 4 + 4 + 4
示例 2:
1 2 3 输入:n = 13 输出:2 解释:13 = 4 + 9
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 func numSquares (n int ) int { dp := make ([]int , n+1 ) for i := range dp { dp[i] = math.MaxInt32 } dp[0 ] = 0 for i := 1 ; i <= n; i++ { for j := 1 ; j*j <= i; j++ { dp[i] = min(dp[i], dp[i-j*j]+1 ) } } return dp[n] }
322.零钱兑换 给你一个整数数组 coins
,表示不同面额的硬币;以及一个整数 amount
,表示总金额。
计算并返回可以凑成总金额所需的 最少的硬币个数 。如果没有任何一种硬币组合能组成总金额,返回 -1
。
你可以认为每种硬币的数量是无限的。
示例 1:
1 2 3 输入:coins = [1, 2, 5], amount = 11 输出:3 解释:11 = 5 + 5 + 1
示例 2:
1 2 输入:coins = [2], amount = 3 输出:-1
示例 3:
1 2 输入:coins = [1], amount = 0 输出:0
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 func coinChange (coins []int , amount int ) int { dp := make ([]int , amount+1 ) for i := range dp { dp[i] = math.MaxInt32 } dp[0 ] = 0 for i := 1 ; i <= amount; i++ { for _, coin := range coins { if coin <= i { dp[i] = min(dp[i], dp[i-coin]+1 ) } } } if dp[amount] == math.MaxInt32 { return -1 } return dp[amount] }
139. 单词拆分 给你一个字符串 s
和一个字符串列表 wordDict
作为字典。如果可以利用字典中出现的一个或多个单词拼接出 s
则返回 true
。
**注意:**不要求字典中出现的单词全部都使用,并且字典中的单词可以重复使用。
示例 1:
1 2 3 输入: s = "leetcode", wordDict = ["leet", "code"] 输出: true 解释: 返回 true 因为 "leetcode" 可以由 "leet" 和 "code" 拼接成。
示例 2:
1 2 3 4 输入: s = "applepenapple", wordDict = ["apple", "pen"] 输出: true 解释: 返回 true 因为 "applepenapple" 可以由 "apple" "pen" "apple" 拼接成。 注意,你可以重复使用字典中的单词。
示例 3:
1 2 输入: s = "catsandog", wordDict = ["cats", "dog", "sand", "and", "cat"] 输出: false
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 func wordBreak (s string , wordDict []string ) bool { dp := make ([]bool , len (s)+1 ) dp[0 ] = true for i := 1 ; i <= len (s); i++ { for j := 0 ; j < i; j++ { if dp[j] && contains(wordDict, s[j:i]) { dp[i] = true break } } } return dp[len (s)] } func contains (wordDict []string , s string ) bool { for _, word := range wordDict { if word == s { return true } } return false }
300.最长递增子序列 给你一个整数数组 nums
,找到其中最长严格递增子序列的长度。
子序列 是由数组派生而来的序列,删除(或不删除)数组中的元素而不改变其余元素的顺序。例如,[3,6,2,7]
是数组 [0,3,1,6,2,2,7]
的子序列。
示例 1:
1 2 3 输入:nums = [10,9,2,5,3,7,101,18] 输出:4 解释:最长递增子序列是 [2,3,7,101],因此长度为 4 。
示例 2:
1 2 输入:nums = [0,1,0,3,2,3] 输出:4
示例 3:
1 2 输入:nums = [7,7,7,7,7,7,7] 输出:1
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 func lengthOfLIS (nums []int ) int { n := len (nums) if n == 0 { return 0 } dp := make ([]int , n) for i := range dp { dp[i] = 1 } maxLen := 1 for i := 1 ; i < n; i++ { for j := 0 ; j < i; j++ { if nums[i] > nums[j] { dp[i] = max(dp[i], dp[j]+1 ) } } maxLen = max(maxLen, dp[i]) } return maxLen }
152. 乘积最大子数组 给你一个整数数组 nums
,请你找出数组中乘积最大的非空连续 子数组(该子数组中至少包含一个数字),并返回该子数组所对应的乘积。
测试用例的答案是一个 32-位 整数。
示例 1:
1 2 3 输入: nums = [2,3,-2,4] 输出: 6 解释: 子数组 [2,3] 有最大乘积 6。
示例 2:
1 2 3 输入: nums = [-2,0,-1] 输出: 0 解释: 结果不能为 2, 因为 [-2,-1] 不是子数组。
数组里存在负数,这会让最大乘积和最小乘积相互转变,所以要同时维护当前最大乘积 maxDp
和当前最小乘积 minDp
。在遍历数组期间,持续更新这两个值以及全局最大乘积 ans
,最终返回 ans
。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 func maxProduct (nums []int ) int { n := len (nums) if n == 0 { return 0 } maxDp, minDp, ans := nums[0 ], nums[0 ], nums[0 ] for i := 1 ; i < n; i++ { mx, mn := maxDp, minDp maxDp = max(mx*nums[i], max(nums[i], mn*nums[i])) minDp = min(mn*nums[i], min(nums[i], mx*nums[i])) ans = max(ans, maxDp) } return ans }