当前位置: 首页 > news >正文

LeetCode Hot 100,快速学习,不断更

        工作做多了有时候需要回归本心,认真刷题记忆一下算法。那就用我这练习时长两年半的代码农民工来尝试着快速解析LeetCode 100吧

快速解析

哈希

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

这题很简单啊,思路也很多

1. 暴力搜索,复杂度 N^2

2. 排序后双指针 复杂度 NlogN

3. 用Hash表,已经遍历过的放入Hash表内记录,看看跟未遍历的求和是不是等于目标,复杂度N

func twoSum(nums []int, target int) []int {hashTable := map[int]int{}for i, x := range nums {if p, ok := hashTable[target-x]; ok {return []int{p, i}}hashTable[x] = i}return nil
}

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

异位词,比如 "abc"和"cba",或者 "acb",反正出现过同样次数的都算是异位词,那么就得想办法,设置一个hash映射,让他们得到的值相等。

1. 先对这个按顺序排序,再拼接起来作为key

2. 整一个26长度数组,统计每个英文字母出现的次数。整个数组作为key用来记录。

128. 最长连续序列 - 力扣(LeetCode)

用哈希直接记录一下整个数组,这样可以去重,还可以以O1的代价来访问值是否存在

然后比如对于值val,如果val-1也在哈希表里,就不计算了(剪枝,降低复杂度)。如果val - 1 不再哈希表里,那么证明val是起点,不断记录val + 1,看看最长能够到多少

func longestConsecutive(nums []int) int {if len(nums) == 0{return 0}cnt := map[int]bool{}for _, v := range nums{cnt[v] = true   }ans := 1for k := range cnt{if cnt[k - 1]{continue}next := k + 1for cnt[next]{next ++ans = max(ans, next - k)}}return ans
}

双指针

283. 移动零 - 力扣(LeetCode)

这题我觉得不应该是easy,高低得是个Middle,我们可以使用双指针,一个指针用来按顺序,另一个用来遍历非零的元素,如果遍历到非零元素,就和第一个指针互换位置。相当于就是把非零的元素全部按顺序填上,那么剩下的就都是0了,因为0会一直被置换到后面,一直往后推。

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

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

传统的双指针,面积是宽度×高度,宽度可以直接用减法,高度就是两边柱子里面最低的。

那么怎么双指针呢,一左一右。那怎么移动指针呢?那就得尝试往更高地方向走,我们先从最矮的一遍移动,每次求max面积,这样就可以求出最多水的容器了。

func maxArea(height []int) int {ans := 0for i, j := 0, len(height) - 1; i < j; {area := (j - i) * min(height[i], height[j])ans = max(area, ans)if height[i] < height[j]{i ++}else{j --}}    return ans
}

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

正常情况之下,我们是不是想要用3个for,这样就是N^3。一般这时候就会想着省时间了,排序,或者二分。因为这里是找3个数,所以先要排序,排序完后就是一个有顺序的数组。

我们用一层循环来遍历第一个数,剩下的复杂度实际上就是两数之和的复杂度了。

这个两数之和,我们可以用双指针,不断地往中间夹缩小范围。这样时间复杂度就小于On了。

func threeSum(nums []int) (ans [][]int) {sort.Ints(nums)n := len(nums)for i := 0; i < n - 2; i ++{if i > 0 && nums[i] == nums[i-1]{continue}j, k := i + 1, n - 1 target := -nums[i]for j < k{        sum := nums[j] + nums[k]if  sum == target{ans = append(ans, []int{nums[i], nums[j], nums[k]})for j < k && nums[j] == nums[j+1]{j++}for j < k && nums[k] == nums[k-1]{k--}j++k--}else if sum < target{j++}else{k--}}}return
}

42. 接雨水 - 力扣(LeetCode)

这题是比较简单的2D接雨水,跟11题非常像,但是又不一样,因为第11题的柱子不占空间,这一题的方块占空间。

我们可以很明显地看到,对于第i个位置可以储藏的雨水,肯定是 min(left, right) - val[i]的,所以我们需要计算左边和右边的高度的最大值,然后再往中间逼近,每一列储存的雨水需要每一步一步慢慢计算累加。

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

滑动窗口

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

维护一个哈希表,如果元素没有在哈希表里,就加进去。如果元素已经在哈希表里了,那么证明此时已经是最大的了,记录一下,左边窗口收缩到符合条件,右边窗口再扩张,不断地调整滑动窗口的大小。

func lengthOfLongestSubstring(s string) int {hash := map[byte]int{}ans := 0startIndex := 0for i := 0; i < len(s); i ++{for hash[s[i]] > 0{x := s[startIndex]startIndex++delete(hash, x)}       hash[s[i]]++ans = max(ans, len(hash))}return ans
}

438. 找到字符串中所有字母异位词 - 力扣(LeetCode)

其实有点类似第49题的。甚至更简单,这边快速写了个go版本,可以参考下
 

func findAnagrams(s string, p string) []int {hash := map[[26]int]bool{}arr := [26]int{}for i := range p{arr[p[i] - 'a'] ++}hash[arr] = truenewArr := [26]int{}pLen := len(p)ans := []int{}for i := 0; i < len(s); i++{newArr[s[i] - 'a'] ++if i >= pLen{newArr[s[i - pLen] - 'a']--}if hash[newArr]{ans = append(ans, i - pLen + 1)}}return ans
}

子串

560. 和为 K 的子数组 - 力扣(LeetCode)

这边的子数组是要连续的,最基础的就是暴力啊,确定一个起点,一个终点。

其实可以认为是双指针,也可以认为是滑动数组。具体的做法也是这样的。如果这个题目的数组值都是正数就很好优化。不过因为可能存在负数,所以我们只能想办法通过空间换时间。就用前缀和吧。具体怎么做呢,可以参考two-sum,把前缀和放到hash里面,然后如果差值存在的话,就有一种情况了,示例代码如下:

func subarraySum(nums []int, k int) int {cnt, pre := 0, 0m := map[int]int{}m[0] = 1for _, v := range nums{pre += vif m[pre - k] > 0{cnt += m[pre - k]}m[pre] ++}return cnt
}

239. 滑动窗口最大值 - 力扣(LeetCode)

先看一眼,优先队列。但是除了python以外,每个语言的优先队列好像都不太好写。最近在写go,写起来还要自己构造struct,实现interface,因此再看一眼,其实可以按照递减顺序来记录的,但是这里面最好记录的是nums数组的index,这样子才号删除掉。

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

76. 最小覆盖子串 - 力扣(LeetCode)

滑动窗口把,或者双指针,实际上都是一个东西。

func minWindow(s string, t string) (ans string) {cnt := make([]int, 128)// less 记录还有几个没有满足的字符less := 0for _, ch := range t {if cnt[ch] == 0 {less++}cnt[ch]++}l := 0for r, ch := range s {cnt[ch]--if cnt[ch] == 0 {less--}for less == 0 {if len(ans) == 0 || r-l < len(ans) {ans = s[l : r+1]}if cnt[s[l]] == 0 {less++}cnt[s[l]]++l++}}return
}

普通数组

53. 最大子数组和 - 力扣(LeetCode)

这题直接贪心,从左到右遍历累加,,如果累加起来小于0,那就干脆前面的直接丢弃掉。重新累加。

func maxSubArray(nums []int) int {ans := nums[0]sum := 0for _, v := range nums{sum += vans = max(ans, sum)if sum < 0{sum = 0}}return ans
}

http://www.dtcms.com/a/312805.html

相关文章:

  • #C语言——刷题攻略:牛客编程入门训练(四):运算
  • Kazam产生.movie.mux后恢复视频为.mp4
  • 小宿科技:AI Agent 的卖铲人
  • zookeeper持久化和恢复原理
  • idea中.xml文件的块注释快捷键
  • Hugging Face 模型文件介绍
  • IDEA查看源码利器XCodeMap插件
  • 【高等数学】第七章 微分方程——第八节 常系数非齐次线性微分方程
  • 【lucene】ByteBuffersIndexInput
  • k8s日志收集
  • Redis面试精讲 Day 8:Stream消息队列设计与实现
  • 对接古老系统的架构实践:封装混乱,走向有序
  • [硬件电路-146]:模拟电路 - DCDC与LDO详解、常见芯片、管脚定义
  • 基于 LangChain + 通义千问 + bge-large 中文 Embedding 搭建一个RAG问答示例
  • TVS二极管数据手册解读
  • 【lucene】ByteBufferGuard
  • Android 之 MVVM架构
  • 【MySQL】MySQL中锁有哪些?
  • Flutter 函数的基本使用
  • day39 力扣198.打家劫舍 力扣213.打家劫舍II 力扣337.打家劫舍 III
  • 常见框架漏洞靶场攻略
  • Java 实现poi方式读取word文件内容
  • 力扣967:连续差相同的数字
  • Mysql1
  • Docker-03.快速入门-部署MySQL
  • python的蛋糕店管理系统
  • MySQL的创建管理表:
  • 求根到叶子节点数字之和
  • 【数据分享】南京诗歌文学地理数据集(获取方式看文末)
  • 电机结构设计与特性曲线分析:基于MATLAB和FEMM的仿真研究