# Hot 100

12 min read
Table of Contents

梦开始的地方

哈希

1. 两数之和

两数之和

暴力枚举

func twoSum(nums []int, target int) []int {
left := 0
for left < len(nums) {
right := left + 1
for right < len(nums) {
if nums[left] + nums[right] == target {
return []int{left, right}
}
right++
}
left++
}
return []int{}
}

哈希表

func twoSum(nums []int, target int) []int {
hashMap := make(map[int]int)
for i := 0; i < len(nums); i++ {
wanted := target - nums[i]
if index, ok := hashMap[wanted]; ok {
return []int{index, i}
}
hashMap[nums[i]] = i
}
return nil
}

49. 字母异位词分组

字母异位词分组

排序 哈希表

func groupAnagrams(strs []string) [][]string {
var ans [][]string
hashMap := make(map[string][]string)
for _, str := range strs {
s := []byte(str)
sort.Slice(s, func(i, j int) bool { return s[i] < s[j] })
sortedStr := string(s)
hashMap[sortedStr] = append(hashMap[sortedStr], str)
}
for _, part := range hashMap {
ans = append(ans, part)
}
return ans
}

存字母计数向量

func groupAnagrams(strs []string) [][]string {
hashMap := make(map[[26]int][]string)
for _, str := range strs {
cnt := [26]int{}
for _, b := range str {
cnt[b-'a']++
}
hashMap[cnt] = append(hashMap[cnt], str)
}
var ans [][]string
for _, v := range hashMap {
ans = append(ans, v)
}
return ans
}

128. 最长连续序列

最长连续序列

排序

func longestConsecutive(nums []int) int {
sort.Slice(nums, func(i, j int) bool { return nums[i] < nums[j] })
cur := 1
maxNum := 1
if len(nums) == 0 {
return 0
}
if len(nums) == 1 {
return 1
}
pre := nums[0]
for i := 1; i < len(nums); i++ {
if nums[i] == pre {
continue
}
if nums[i] == pre + 1 {
cur++
} else if nums[i] > pre + 1 {
maxNum = max(cur, maxNum)
cur = 1
}
pre = nums[i]
}
return max(maxNum, cur)
}

官方题解没给排序,结果排序更快且内存更少,那是何意味

哈希表去重

func longestConsecutive(nums []int) int {
numSet := make(map[int]bool)
for _, num := range nums {
numSet[num] = true
}
longestStreak := 0
for num := range numSet {
if !numSet[num - 1] {
currentNum := num
currentStreak := 1
for numSet[currentNum + 1] {
currentNum++
currentStreak++
}
if longestStreak < currentStreak {
longestStreak = currentStreak
}
}
}
return longestStreak
}

双指针

283. 移动零

移动零

双指针交换

func moveZeroes(nums []int) {
left := 0
for right := 0; right < len(nums); right++ {
if nums[right] != 0 {
nums[left], nums[right] = nums[right], nums[left]
left++
}
}
}

11. 盛最多水的容器

盛最多水的容器

双指针+贪心

func maxArea(height []int) int {
left, right := 0, len(height) - 1
var s, ans int
for left < right {
s = (right - left)*min(height[left], height[right])
if s > ans {
ans = s
}
if height[left] >= height[right] {
right--
} else {
left++
}
}
return ans
}

15. 三数之和

三数之和

定1双指针另外两个

func threeSum(nums []int) [][]int {
var ans [][]int
sort.Slice(nums, func(i, j int) bool { return nums[i] <= nums[j] })
for i := 0; i < len(nums)-2; i++ {
if i > 0 && nums[i - 1] == nums[i] {
continue
}
x := nums[i]
left := i + 1
right := len(nums) - 1
for left < right {
y := nums[left] + nums[right]
if y + x == 0 {
ans = append(ans, []int{x, nums[left], nums[right]})
for nums[right] == nums[right - 1] && left < right {
right--
}
for nums[left] == nums[left + 1] && left < right {
left++
}
left++
right--
} else if y + x > 0 {
right--
} else if y + x < 0 {
left++
}
}
}
return ans
}

可以稍微优化一点

+剪枝+语法优化

func threeSum(nums []int) [][]int {
slices.Sort(nums)
length := len(nums)
ans := make([][]int, 0)
for i, num := range nums {
if num > 0 {
break
}
if i > 0 && nums[i - 1] == num {
continue
}
target := -num
left, right := i + 1, length - 1
for left < right {
sum := nums[left] + nums[right]
if sum > target {
right--
} else if sum < target {
left++
} else {
for left < right && nums[left] == nums[left + 1] {
left++
}
for left < right && nums[right] == nums[right - 1] {
right--
}
ans = append(ans, []int{num, nums[left], nums[right]})
left++
right--
}
}
}
return ans
}

slices.Sort相比sort.Slice 前者为泛型排序,不用闭包性能更好

nSum

func nSum(nums []int, n int, start int, target int) [][]int {
res := [][]int{}
length := len(nums)
if n < 2 || length-start < n {
return res
}
if n == 2 {
left, right := start, length-1
for left < right {
sum := nums[left] + nums[right]
if sum == target {
res = append(res, []int{nums[left], nums[right]})
for left < right && nums[left] == nums[left+1] {
left++
}
for left < right && nums[right] == nums[right-1] {
right--
}
left++
right--
} else if sum < target {
left++
} else {
right--
}
}
return res
}
for i := start; i < length; i++ {
if i > start && nums[i] == nums[i-1] {
continue
}
if nums[i]*n > target {
break
}
if nums[length-1]*n < target {
break
}
sub := nSum(nums, n-1, i+1, target-nums[i])
for _, arr := range sub {
res = append(res, append([]int{nums[i]}, arr...))
}
}
return res
}

42. 接雨水

接雨水

长官我只会双指针

func trap(height []int) int {
l := len(height)
left := 0
right := l - 1
leftMax := 0
rightMax := 0
ans := 0
for left < right {
leftMax = max(leftMax, height[left])
rightMax = max(rightMax, height[right])
if height[left] < height[right] {
ans += leftMax - height[left]
left++
} else {
ans += rightMax - height[right]
right--
}
}
return ans
}

滑动窗口

3. 无重复字符的最长子串

无重复字符的最长子串

哈希+滑动窗口

func lengthOfLongestSubstring(s string) int {
hashMap := make(map[byte]bool)
left := 0
maxLen := 0
for right := 0; right < len(s); right++ {
for hashMap[s[right]] {
delete(hashMap, s[left])
left++
}
hashMap[s[right]] = true
if right - left + 1 > maxLen {
maxLen = right - left + 1
}
}
return maxLen
}

4ms

+写法优化

func lengthOfLongestSubstring(s string) int {
res, left := 0, 0
cnt := [128]int{}
for right := 0; right < len(s); right++ {
cnt[s[right]]++
for cnt[s[right]] >= 2 {
cnt[s[left]]--
left++
}
res = max(res, right-left+1)
}
return res
}

0ms

438. 找到字符串中所有字母异位词

找到字符串中所有字母异位词

定长窗口 26字母

func findAnagrams(s string, p string) []int {
sLen, pLen := len(s), len(p)
if sLen < pLen {
return []int{}
}
ans := []int{}
var sCount, pCount [26]int
for i, ch := range p {
sCount[s[i]-'a']++
pCount[ch-'a']++
}
if pCount == sCount {
ans = append(ans, 0)
}
for i, ch := range s[:sLen - pLen] {
sCount[ch-'a']--
sCount[s[i+pLen]-'a']++
if sCount == pCount {
ans = append(ans, i + 1)
}
}
return ans
}

子串

560. 和为 K 的子数组

和为 K 的子数组

暴力+前缀和

func subarraySum(nums []int, k int) int {
n := len(nums)
sum := make([]int, n+1)
for i := 0; i < n; i++ {
sum[i+1] = sum[i] + nums[i]
}
ans := 0
for i := 0; i < n; i++ {
for j := i; j < n; j++ {
if sum[j+1]-sum[i] == k {
ans++
}
}
}
return ans
}

哈希表+前缀和

func subarraySum(nums []int, k int) int {
count := 0
prefix := 0
m := map[int]int{0: 1}
for _, num := range nums {
prefix += num
if v, ok := m[prefix-k]; ok {
count += v
}
m[prefix]++
}
return count
}

239. 滑动窗口最大值

滑动窗口最大值

双端队列

func maxSlidingWindow(nums []int, k int) []int {
n := len(nums)
var ans []int
deque := []int{}
for i := 0; i < n; i++ {
if len(deque) > 0 && deque[0] < i-k+1 {
deque = deque[1:]
}
for len(deque) > 0 && nums[deque[len(deque)-1]] < nums[i] {
deque = deque[:len(deque)-1]
}
deque = append(deque, i)
if i >= k-1 {
ans = append(ans, nums[deque[0]])
}
}
return ans
}

但这样写没有这个写法快

func maxSlidingWindow(nums []int, k int) []int {
if len(nums) == 0 || k == 0 {
return []int{}
}
n := len(nums)
result := make([]int, 0, n - k + 1)
deque := make([]int, 0 , k)
for i := 0; i < n; i++ {
if len(deque) > 0 && deque[0] < i - k + 1 {
deque = deque[1:]
}
for len(deque) > 0 && nums[deque[len(deque) - 1]] < nums[i] {
deque = deque[:len(deque) - 1]
}
deque = append(deque, i)
if i >= k-1 {
result = append(result, nums[deque[0]])
}
}
return result
}

区别就在result := make([]int, 0, n - k + 1)deque := make([]int, 0 , k) 就单单因为提前分配了容量 make(type, size, cap) 第一个为8ms而第二个为1ms

这不神奇吗

76. 最小覆盖子串

最小覆盖子串

滑动窗口+哈希表

func minWindow(s string, t string) string {
need := make(map[byte]int)
window := make(map[byte]int)
for i := 0; i < len(t); i++ {
need[t[i]]++
}
left, count := 0, 0
start, minLen := 0, len(s)+1
for right := 0; right < len(s); right++ {
c := s[right]
if _, ok := need[c]; ok {
window[c]++
if window[c] == need[c] {
count++
}
}
for count == len(need) {
if right-left+1 < minLen {
start = left
minLen = right-left+1
}
d := s[left]
left++
if _, ok := need[d]; ok {
if window[d] == need[d] {
count--
}
window[d]--
}
}
}
if minLen == len(s) + 1 {
return ""
}
return s[start : start + minLen]
}

29ms

func minWindow(s string, t string) string {
n, m := len(s), len(t)
if n < m {
return ""
}
var c1, c2 [60]int
tot := 0
for i := 0; i < m; i++ {
idx := getIdx(t[i])
if c1[idx] == 0 {
tot++
}
c1[idx]++
}
ans := ""
for i, j := 0, 0; i < n; i++ {
idx1 := getIdx(s[i])
c2[idx1]++
if c2[idx1] == c1[idx1] {
tot--
}
for j < i {
idx2 := getIdx(s[j])
if c2[idx2] > c1[idx2] {
c2[idx2]--
j++
} else {
break
}
}
if tot == 0 {
if ans == "" || len(ans) > i-j+1 {
ans = s[j : i+1]
}
}
}
return ans
}
func getIdx(x byte) int {
if x >= 'A' && x <= 'Z' {
return int(x - 'A' + 26)
}
return int(x - 'a')
}

0ms

普通数组

53. 最大子数组和

最大子数组和

前缀和

func maxSubArray(nums []int) int {
minPre := 0
curPre := 0
maxSum := nums[0]
for _, x := range nums {
curPre += x
if curPre - minPre > maxSum {
maxSum = curPre - minPre
}
if curPre < minPre {
minPre = curPre
}
}
return maxSum
}

分治

不太会,以后再说

func maxSubArray(nums []int) int {
return get(nums, 0, len(nums) - 1).mSum;
}
func pushUp(l, r Status) Status {
iSum := l.iSum + r.iSum
lSum := max(l.lSum, l.iSum + r.lSum)
rSum := max(r.rSum, r.iSum + l.rSum)
mSum := max(max(l.mSum, r.mSum), l.rSum + r.lSum)
return Status{lSum, rSum, mSum, iSum}
}
func get(nums []int, l, r int) Status {
if (l == r) {
return Status{nums[l], nums[l], nums[l], nums[l]}
}
m := (l + r) >> 1
lSub := get(nums, l, m)
rSub := get(nums, m + 1, r)
return pushUp(lSub, rSub)
}
func max(x, y int) int {
if x > y {
return x
}
return y
}
type Status struct {
lSum, rSum, mSum, iSum int
}

56. 合并区间

合并区间

一般通过写法

func merge(intervals [][]int) [][]int {
var ans [][]int
var left, right int
sort.Slice(intervals, func(i, j int) bool { return intervals[i][0] < intervals[j][0] })
for i := 0; i < len(intervals); i++ {
left = intervals[i][0]
right = intervals[i][1]
for i < len(intervals)-1 && intervals[i+1][0] <= right {
right = max(intervals[i+1][1], right)
i++
}
ans = append(ans, []int{left, right})
}
return ans
}

排序+原地修改

func merge(intervals [][]int) [][]int {
if (len(intervals) == 1) {
return intervals
}
sort.Slice(intervals, func(i, j int) bool {
return intervals[i][0] < intervals[j][0]
})
res := make([][]int, 0)
res = append(res, intervals[0])
for i := 1; i < len(intervals); i++ {
if (res[len(res)-1][1] >= intervals[i][0]) {
res[len(res)-1][1] = max(res[len(res)-1][1], intervals[i][1])
} else {
res = append(res, intervals[i])
}
}
return res
}

189. 轮转数组

轮转数组


More Posts