LeetCode面试经典150题梳理

link:https://leetcode.cn/studyplan/top-interview-150/

日期题号备注
2025.5.2288. 合并两个有序数组 - 力扣(LeetCode)通过双指针法从后向前合并来解决,避免覆盖nums1中的元素
2025.5.2327. 移除元素 - 力扣(LeetCode)

用快慢指针

slow用来标识有效元素的下标

fast用来遍历整个数组

slow和fast都从下标0开始

如果nums[fast] != val, 将fast的值复制到slow的位置,然后移动slow

2025.5.2426. 删除有序数组中的重复项 - 力扣(LeetCode)

用快慢指针

fast用来遍历数组

slow标识新元素的下标

需要时刻考虑fast指针是否越界的问题

2025.5.2580. 删除有序数组中的重复项 II - 力扣(LeetCode)

用快慢指针

长度小于2,直接返回,slow和fast都从下标2开始

slow指针表示修改后数组的下标,fast遍历整个数组

比较 nums[fast] == nums[slow-2]:true, continue; false,给slow赋值

2025.5.26169. 多数元素 - 力扣(LeetCode)

最简单的:摩尔投票法

初始化候选人和计数器

遍历数组元素,相同元素则计数器+1,不同则-1

当计数器归零时更换候选元素

最终候选人即为所求

错误点:在count变为0时,将候选人设置为当前元素,并将count重置为1

2025.5.27189. 轮转数组 - 力扣(LeetCode)

反转直接写for循环

需要将k取模,来处理k大于数组长度的情况

2025.5.28121. 买卖股票的最佳时机 - 力扣(LeetCode)

直接跳过,自己做出来的

类似动态规划的思想:

minPrice 记录当前最低的股票价格

maxProfit 记录已知的最大利润

2025.5.29122. 买卖股票的最佳时机 II - 力扣(LeetCode)

用贪心算法,捕捉所有上升趋势的机会,并且就在第一天买,第二天卖

135. 分发糖果 - 力扣(LeetCode)

贪心算法,维护两个数组

从左到右:确保右边孩子的糖果比左边孩子多

从右到左:确保左边孩子的糖果比右边孩子多

没考虑到的地方:当前评分不大于前一个时,应该将糖果数设为1,而不是保持前一个的值

两个数组中取最大值

2025.5.3055. 跳跃游戏 - 力扣(LeetCode)

动态规划(自己想到的):

  • 维护一个bool数组loc
  • loc[0] = true
  • 遍历nums数组,loc[i]为true,则把 i 到 i+nums[i] 的所有loc都置为true。 如果loc[len(nums)-1] == true了,return true
  • 如果遍历到某个位置loc[i]为false了,return false

贪心算法:

  • 维护一个maxReach
  • 遍历数组,maxReach = max(maxReach, nums[i] + i)
  • 如果 maxReach < i, return false;
  • 如果 maxReach > len(nums) - 1, return true;
2025.6.245. 跳跃游戏 II - 力扣(LeetCode)

(没想到)

用贪心算法:每一步都尽量跳得最远,这样才能保证跳跃次数最少。

end = 0, farthest = 0, jump = 0。

end: 当前这一跳的最远位置;farthest:当前跳跃范围内,通过每一步能到达的最远位置。

每当你走到end时(即i==end),说明你需要跳一次,此时jumps++,并把end更新为farthest。

只要能覆盖到最后一个元素,就可以结束了。

2025.6.3274. H 指数 - 力扣(LeetCode)

(想到了暴力解法)

从数组里面的最大值开始遍历 value

找到符合 citations[i] >= value 的个数 count

如果count == value, 返回value

不然继续

优化: 排序 + 一次遍历

先把数组排序,第i篇论文的引用数是citation[n-i]

从前向后找,找到第一个 citations[i] >= n-i,说明有 n-i 篇论文引用不少于 n-i 次

2025.6.4380. O(1) 时间插入、删除和获取随机元素 - 力扣(LeetCode)

用空间换时间

  • 定义一个map[int]int数组:key是插入的值,value是元素在keys数组中的索引
  • 插入元素的时候,把索引更新到value的位置
  • 删除元素的时候,先查找元素是否存在,如果存在,找到其索引,然后将Keys末尾的元素移到该索引的位置,更新map中该末尾元素的索引,最后从Keys中删除末尾元素
  • rand种子的设置需要挪到最前面

初始化map的方法:make(map[int]int)

判断key是否存在的方法: index, exists := this.Mapping[val]

删除key的方法: delete(this.Mapping, val)

设置随机种子:rand.Seed(time.Now().UnixNano()), keys[rand.Intn(len(keys))]

2025.6.5238. 除自身以外数组的乘积 - 力扣(LeetCode)

自己想到的:

  1. 维护两个数组:当前数左边/右边所有数的乘积
  2. 初始化数组:nums1 := make([]int, len(nums))
42. 接雨水 - 力扣(LeetCode)

动态规划:两个数组记录左右两边的最大值

当前网格储水量 = min(leftMax[i], rightMax[i]) - 当前高度

2025.6.613. 罗马数字转整数 - 力扣(LeetCode)

从左到右累加

  1. 当前字符 >= 后一个字符,result += current_value, i+1
  2. 当前字符 < 后一个字符, result += (next_value - current_value), i+2
  3. 初始化map的方法 mapping := map[byte]int{...}
2025.6.9134. 加油站 - 力扣(LeetCode)

想到了暴力解法, 拼接数组的逻辑:

  • a := nums[k:]
  • b := nums[:k]
  • result := append(a, b ...)

贪心算法:

  • 一次遍历:记录总油量totalGas和当前油量currentGas。currentGas不足时,重置起点为下一个加油站;totalGas不足时,无法完成任务
2025.6.1012. 整数转罗马数字 - 力扣(LeetCode)

贪心算法:

  •         维护一个从大到小的结构体数组, 每次减去可减去的最大数
type romanNumeral struct {
    value  int
    symbol string
}

var numerals = []romanNumeral{
    {1000, "M"},
    ......
}
  •       使用string builder来构建结果
var b strings.Builder
    for _, n := range numerals {
        for num >= n.value {
            b.WriteString(n.symbol)
            num -= n.value
        }
    }

2025.6.1158. 最后一个单词的长度 - 力扣(LeetCode)

自己想到的:

        先跳过末尾的所有空格,再直接遍历找出末尾最后一个单词的长度

2025.6.1214. 最长公共前缀 - 力扣(LeetCode)自己想到的:逐个比较每个字符的最长公共前缀
151. 反转字符串中的单词 - 力扣(LeetCode)自己想到的:
  • 原来有多个空格,转换后还有一个空格的解法:strings.Fields
  • 反转字符的解法:从后向前遍历
2025.6.1628. 找出字符串中第一个匹配项的下标 - 力扣(LeetCode)

用双指针

slow: 用来标志第slow个字符被检查过是否符合了,取值 0 到 两个长度之差

比较的时候应该是slow+j和j的下标进行比较

2025.6.17125. 验证回文串 - 力扣(LeetCode)

先都转换成小写,在保留所有的小写字母,最后双指针判断是否是回文串

// 编译超时改进拼接字符串:

for _, ch := range s {

    if unicode.IsLetter(ch) || unicode.IsDigit(ch) {

        filtered = append(filtered, unicode.ToLower(ch))

    }

}

2025.6.18392. 判断子序列 - 力扣(LeetCode)自己想到的: 

双指针

167. 两数之和 II - 输入有序数组 - 力扣(LeetCode)

想到了暴力解法,也可以用双指针

i=0,j = len(numbers) - 1: 两数之和<target,i++; 两数之和>target,j--;

2025.6.1911. 盛最多水的容器 - 力扣(LeetCode)

想到了贪心算法, 最大水量 = width * min(height)

没想到:从两边开始向中间挪最短的边,不断更新最大水量

2025.6.2015. 三数之和 - 力扣(LeetCode)

想到:先排序,在固定一个值后用双指针

没想到的:需要跳过重复的值,跳过后记得更新双指针

2025.6.23209. 长度最小的子数组 - 力扣(LeetCode)

没想到:可以用滑动窗口: left, right := 0, 0

向右移动right,直到 sum >= target, 设置一个变量记录result

移动左窗口来缩小滑动窗口;

继续移动right,重复上面的步骤

2025.6.273. 无重复字符的最长子串 - 力扣(LeetCode)

想到思路,实现卡了好几天:

也用滑动窗口,left,right

用一个map[byte]int来维护,int可以下标的值

left,right双指针:

  1.  mapping[right]存在就更新left 到重复字符的下一个位置
  2. 更新字符的最新索引
  3. 计算result
2025.6.3036. 有效的数独 - 力扣(LeetCode)

自己没有想到的:

用3个二维数组是否存在的状态

  • rows[i][j]:第i行中是否出现了数字j+1
  • cols[i][j]:第i列中是否出现了数字j+1
  • boxes[boxIndex][num]:第boxIndex个小方格里是否有数字num+1;boxIndex=(row/3)×3+(col/3)

byte 转int:intVal, _ := strconv.Atoi(string(val))

初始化数组: var rows [9][9]bool

2025.7.1383. 赎金信 - 力扣(LeetCode)

自己想到的

直接用一个数组维护magazine; index = char - 'a',

遍历ransomNote,存在的话val-1, 不存在return false

2025.7.254. 螺旋矩阵 - 力扣(LeetCode)

没想到,边界控制法

从左到右 -> 从上到下 -> 从右到左 -> 从下到上

更新位置的时候应该在if条件里面

从右到左应该检查上下边界

从下到上应该检查左右边界

2025.7.348. 旋转图像 - 力扣(LeetCode)

matrix[i][j] 和 matrix[n-1-i][n-1-j]互换顺序

上下的行互换顺序

沿着对角线互换顺序没想到:

for i := 0; i < n; i++ {
	for j := i+1; j < n; j++ {
		matrix[i][j], matrix[j][i] = matrix[j][i], matrix[i][j]
    }
}

2025.7.473. 矩阵置零 - 力扣(LeetCode)

自己想到的:

先遍历一遍数组把需要置为0的行和列都存下来,然后直接赋0

2025.7.7205. 同构字符串 - 力扣(LeetCode)

没想到,维护两个mapping s2t 和 t2s

把t和s的值相互映射,确认是否有重复的映射关系

2025.7.8290. 单词规律 - 力扣(LeetCode)

自己想到的,还是用两个数组维护映射关系

p2s := make(map[byte]string)

s2p := make(map[string]byte)

p2s[char] != ""  s2p[str] > 0

2025.7.10242. 有效的字母异位词 - 力扣(LeetCode)

自己想到的,注意遍历string数组的方式:

mapping := make(map[rune]int)

for _, c := range s {...}

2025.7.1449. 字母异位词分组 - 力扣(LeetCode)

自己没想到

用计数法,记下26个字母每个字母出现的次数,然后拼接成一个string

相同key的就是字母异位

2025.7.151. 两数之和 - 力扣(LeetCode)

自己想到的

用一个map[int]int数组保存,key是当前值,value是下标

2025.7.17202. 快乐数 - 力扣(LeetCode)

思路没想到,代码自己写的

使用一个map集合来判断是否出现了重复的数字

出现了就不是快乐数字,没出现就是

2025.7.18219. 存在重复元素 II - 力扣(LeetCode)

用一个map[int]int来存储:key是nums[i],value 是i

如果map[nums[i]]已经存在:

if abs(i - j) <= k, 成立就return true

else map[nums[i]] = 新的i。

如果map[nums[i]]不存在, map[nums[i]] = i

继续循环,直到最后一个值还不成立,return false

math.Abs(float64(index - i)) <= float64(k)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值