惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

SecWiki News
SecWiki News
I
InfoQ
The Cloudflare Blog
人人都是产品经理
人人都是产品经理
博客园 - Franky
T
Tailwind CSS Blog
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
量子位
博客园_首页
罗磊的独立博客
V
V2EX
李成银的技术随笔
大猫的无限游戏
大猫的无限游戏
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
T
True Tiger Recordings
Vercel News
Vercel News
Cyberwarzone
Cyberwarzone
Cisco Talos Blog
Cisco Talos Blog
F
Fox-IT International blog
D
Darknet – Hacking Tools, Hacker News & Cyber Security
M
Microsoft Research Blog - Microsoft Research
Know Your Adversary
Know Your Adversary
爱范儿
爱范儿
The Register - Security
The Register - Security
G
Google Developers Blog
The Hacker News
The Hacker News
Malwarebytes
Malwarebytes
S
Securelist
博客园 - 三生石上(FineUI控件)
Jina AI
Jina AI
T
Threat Research - Cisco Blogs
T
The Exploit Database - CXSecurity.com
S
SegmentFault 最新的问题
博客园 - 叶小钗
F
Fortinet All Blogs
Apple Machine Learning Research
Apple Machine Learning Research
宝玉的分享
宝玉的分享
博客园 - 聂微东
T
Threatpost
博客园 - 【当耐特】
D
Docker
P
Privacy & Cybersecurity Law Blog
www.infosecurity-magazine.com
www.infosecurity-magazine.com
G
GRAHAM CLULEY
V
Visual Studio Blog
C
Cisco Blogs
IT之家
IT之家
S
Security Archives - TechRepublic
Latest news
Latest news
阮一峰的网络日志
阮一峰的网络日志

蛮荆

如何获取更多的免费服务器 Kubernetes 调度器队列 - 设计与实现 Kubernetes 调度器 - 核心流程 Kubernetes Networking Model & CNI Kubernetes 控制器管理总结 Kubernetes CronJob 设计与实现 Kubernetes Job 设计与实现 Kubernetes HPA 设计与实现 Kubernetes Deployment 滚动更新实现原理 Kubernetes GC 设计与实现 Kubernetes Pod 驱逐 - 设计与实现 Kubernetes Daemonset 设计与实现 Kubernetes ReplicaSet 设计与实现 Kubernetes EndPoint 设计与实现 Kubernetes Informer 设计与实现 降本增效之应用优化 (三) 日志存储与检索 Kubernetes Pod 设计与实现 - 创建流程 Kubernetes 探针设计与实现 Unix 编程艺术名句摘录 Kubernetes - CRI 概述 Golang 编译速度为什么这么快? Kubernetes Pod 设计与实现 - Pause 容器 Kubernetes - kube-proxy 代理模式工程优化 Kubernetes 应用最佳实践 - 优雅关闭长连接 Kubernetes Service 类型和会话亲和性 Kubernetes 为什么需要 Ingress Kubernetes 架构 - 控制平面和数据平面 降本增效之应用优化 (二) 大报表 Go 语言如何获取 CPU 利用率 降本增效之应用优化 (一) Redis 业务规则引擎演变过程简述 微服务中的熔断算法 漏桶算法和令牌桶算法 jsonparser 为什么比标准库的 encoding/json 快 10 倍 ? zap 高性能设计与实现 HTTP Router 算法演进 布谷鸟过滤器 fastcache 高性能设计与实现 Web 常见的三个安全问题 ants Code Reading 布谷鸟过滤器 Go 线程安全 map 方案选型 布隆过滤器 死锁、活锁、饥饿、自旋锁 sync.Pool Code Reading Go 内存管理概述 Go netpoll Code Reading goroutine 泄漏与检测 time/Timer Code Reading GMP Scheduler Code Reading Go channel 的 15 条规则和底层实现 为什么 Linux “一切皆文件” context.Context Code Reading runtime/HACKING.md Goland 最佳实践 互联网开发与金庸武学 为什么 Redis 6.0 引入多线程模型? Kubernetes 应用最佳实践 - 金丝雀发布 容器中如何正确配置 GOMAXPROCS ? singleflight Code Reading sync.Map Code Reading sync.Cond Code Reading sync.WaitGroup Code Reading sync.RWMutex Code Reading sync.Mutex Code Reading sync.Once Code Reading Go 无锁编程 sync/atomic Code Reading goroutine 交替打印奇偶数 GODEBUG Go 并发模式 Go 汇编 UUID 通用技术选型 Kubernetes 应用最佳实践 - 水平自动伸缩 Go 高性能 Tips fasthttp 为什么比标准库 net/http 快 10 倍 ? 技术文章配图指南 ChatGPT 初体验 Docker 网络原理概览 iptables 的五表五链 Kubernetes 应用最佳实践 - 亲和性和污点容忍度 Go 的反射与三大定律 Docker 官方提供的最佳实践 Go 语言内置的设计模式 HTTP1 到 HTTP3 的工程优化 Kubernetes 应用最佳实践 - Sidecar 模式 Kubernetes 应用最佳实践 - init 容器和钩子函数 为什么 recover 必须在 defer 中调用? 为什么 defer 的执行顺序和注册顺序不同? Go map 设计与实现 Go 切片扩容底层实现 Go 语言中的零拷贝 Go Delve 云原生和边缘计算简介 Kubernetes Pod 服务质量等级 Kubernetes 应用最佳实践 - 探针 Kubernetes 应用最佳实践 - 资源请求和限制 CDN 原理 Kubernetes 应用最佳实践 - 开篇 缓存策略和模式
LeetCode Hash 刷题模板
2022-03-15 · via 蛮荆

2022-03-15 算法 LeetCode

数学概念

在数学中,单射(injection)、满射(surjection)和双射(bijection)是描述函数之间关系的重要概念,通常用于描述两个集合之间的映射关系。

单射

对于集合 A 中的每个不同的元素,在集合 B 中都有唯一的映射元素。

单射但非满射

满射

对于集合 A 中的每个不同的元素,在集合 B 中都至少有一个的映射元素。

满射但非单射

双射

同时满足单射和满射, 对于集合 A 中的每个不同的元素,在集合 B 中都有唯一的映射元素,同时,对于集合 B 中的每个不同的元素,在集合 A 中都有唯一的映射元素,也就是集合 A 和 集合 B 中的元素是一一对应的。

双射

哈希类型题目

将 Hash 类题目从本质进行分类,基本可以分为单射、满射、双射映射问题。

Hash 类型题目应该是所有题型中最简单的了,尤其是使用 Go 写过业务代码之后,这种体验应该会更深 ~ 单纯的 Hash 类型题目基本都是简单类题目,所以整体的刷题体验还是很愉快的。

但是有一个比较踩坑的地方在于:虽然很多题目都可以使用 Hash 来开始暴力解题,但是这些题目的考点都不在 Hash 上面,毕竟 Hash 带来的额外空间开销是不可忽视的,和位运算一样,Hash 也属于低频考题,如果面试中遇到的题目除了 Hash 之外想不到其他解题方法,可以先使用 Hash 给出题解答案,然后根据面试官的反馈来确定下一步。

Golang Set

Go 语言中没有内置的 Set 数据类型,所以遇到需要使用 Set 的场景,需要自定义一个实现,下面给出一个通用的模板。

// 集合初始化
set := make(map[int]struct{})

// 向集合插入一些数据
for i := range nums {
    set[nums[i]] = struct{}{}
}

// 查找某个元素是否存在于集合中
if _, ok := set[v-1]; ok {
    ...
}	

空间使用技巧

如果题目参数给出了数值范围,例如纯小写字母、纯大写字母,这时候可以使用对应长度数组代替 Map, 提升细微的时间效率和空间效率,下面列举了一些典型的使用场景。

参数由任意小写 (大写) 字母组成

可以直接定义一个长度为 26 的数组来充当 Map 数据类型:

m := [26]int{}

参数由任意 ASCII 字符组成

可以直接定义一个长度为 128 的数组来充当 Map 数据类型:

m := [128]int{}

参数由任意 0 - 9 数字组成

可以直接定义一个长度为 10 的数组来充当 Map 数据类型:

m := [10]int{}

💡 典型题目

前文中提到,Hash 类型题目基本可以归类为单射、满射、双射映射问题,那么解题过程中唯一需要确认的就是:输入集合是什么?输出集合是什么? 大多数问题直接套用这个模板即可,解题过程就和写业务代码差不多。

1. 两数之和

给定一个整数数组 nums 和一个整数目标值 target,请你在该数组中找出 和为目标值 target 的那 两个 整数,并返回它们的数组下标。

## 示例来自:https://leetcode.cn
示例 1:

输入:nums = [2,7,11,15], target = 9
输出:[0,1]
解释:因为 nums[0] + nums[1] == 9 ,返回 [0, 1] 。
示例 2:

输入:nums = [3,2,4], target = 6
输出:[1,2]
示例 3:

输入:nums = [3,3], target = 6
输出:[0,1]

快速套模板

  • 确定题型:这是一个根据输出集合求解输入集合的问题
  • 输出集合:参数数组元素集合 (只要集合不为空就存在题目要求的解)
  • 输入集合:参数 target - 参数数组各元素的差 形成的集合

图解快速套模板

// 题解代码
func TwoSum(nums []int, target int) []int {
	m := make(map[int]int)

	for i, num := range nums {
		if diff, ok := m[target-num]; ok {
			return []int{diff, i}
		}
		m[num] = i
	}

	return []int{}
}

2. 赎金信

给你两个字符串:ransomNote 和 magazine ,判断 ransomNote 能不能由 magazine 里面的字符构成。

如果可以,返回 true ;否则返回 false 。magazine 中的每个字符只能在 ransomNote 中使用一次。

## 示例来自:https://leetcode.cn

示例 1:

输入:ransomNote = "a", magazine = "b"
输出:false
示例 2:

输入:ransomNote = "aa", magazine = "ab"
输出:false
示例 3:

输入:ransomNote = "aa", magazine = "aab"
输出:true

快速套模板

  • 确定题型:求解两个字符串是否为满射
  • 输出集合:参数 magazine 字符串
  • 输入集合:参数 ransomNote 字符串

图解快速套模板

func canConstruct(ransomNote string, magazine string) bool {
    m := [26]int{}

    for _, char := range magazine {
        m[char-'a']++
    }

    for _, char := range ransomNote {
        m[char-'a']--
        if m[char-'a'] < 0 {
            return false
        }
    }
    
    return true
}

3. 同构字符串

给定两个字符串 s 和 t ,判断它们是否是同构的。

如果 s 中的字符可以按某种映射关系替换得到 t ,那么这两个字符串是同构的。

## 示例来自:https://leetcode.cn

示例 1:

输入:s = "egg", t = "add"
输出:true
示例 2:

输入:s = "foo", t = "bar"
输出:false
示例 3:

输入:s = "paper", t = "title"
输出:true

快速套模板

  • 确定题型:求解两个字符串是否为双射,函数为字符串中每个字符的位置对应
  • 输出集合:参数 s 中每个字符出现的位置
  • 输入集合:参数 t 中每个字符出现的位置

图解快速套模板

func isIsomorphic(s string, t string) bool {
	sMap := [128]int{}
	tMap := [128]int{}

	// 只需要记录连续字符的位置相对性
	for i := range s {
		if sMap[s[i]] != tMap[t[i]] {
			return false
		} else {
			if sMap[s[i]] == 0 {
				// 更新字符位置为最新索引 + 1
				// i + 1 是为了避免 map value 默认值为 0 引起的错误
				sMap[s[i]] = i + 1
				tMap[t[i]] = i + 1
			}
		}
	}

	return true
}

4. 单词规律

给定一种规律 pattern 和一个字符串 s ,判断 s 是否遵循相同的规律。

## 示例来自:https://leetcode.cn

示例1:

输入: pattern = "abba", s = "dog cat cat dog"
输出: true
示例 2:

输入:pattern = "abba", s = "dog cat cat fish"
输出: false
示例 3:

输入: pattern = "aaaa", s = "dog cat cat dog"
输出: false

快速套模板

  • 确定题型:求解两个字符串中是否为双射,函数为单个字符和多个字符的的位置对应
  • 输出集合:参数字符串 pattern
  • 输入集合:参数字符串 s

图解快速套模板

func wordPattern(pattern string, s string) bool {
	// 双射解题
	wordToChar := make(map[string]byte)
	charToWord := make(map[byte]string)

	words := strings.Split(s, " ")
	if len(pattern) != len(words) {
		return false
	}

	for i, word := range words {
		char := pattern[i]
		// 如果不满足双射条件,直接返回
		if wordToChar[word] > 0 && wordToChar[word] != char {
			return false
		}
		if len(charToWord[char]) > 0 && charToWord[char] != word {
			return false
		}

		wordToChar[word] = char
		charToWord[char] = word
	}

	return true
}