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

推荐订阅源

PCI Perspectives
PCI Perspectives
Microsoft Security Blog
Microsoft Security Blog
MongoDB | Blog
MongoDB | Blog
T
The Blog of Author Tim Ferriss
罗磊的独立博客
人人都是产品经理
人人都是产品经理
The Cloudflare Blog
Engineering at Meta
Engineering at Meta
Y
Y Combinator Blog
宝玉的分享
宝玉的分享
Recorded Future
Recorded Future
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
月光博客
月光博客
Recent Announcements
Recent Announcements
Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
D
Darknet – Hacking Tools, Hacker News & Cyber Security
Apple Machine Learning Research
Apple Machine Learning Research
T
Threatpost
The GitHub Blog
The GitHub Blog
M
MIT News - Artificial intelligence
Scott Helme
Scott Helme
P
Palo Alto Networks Blog
T
Tenable Blog
P
Privacy International News Feed
V
Visual Studio Blog
F
Fortinet All Blogs
酷 壳 – CoolShell
酷 壳 – CoolShell
I
Intezer
cs.CL updates on arXiv.org
cs.CL updates on arXiv.org
AI
AI
cs.CV updates on arXiv.org
cs.CV updates on arXiv.org
S
Security Affairs
S
SegmentFault 最新的问题
C
Cisco Blogs
博客园 - 聂微东
MyScale Blog
MyScale Blog
V
Vulnerabilities – Threatpost
量子位
T
The Exploit Database - CXSecurity.com
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
Security Latest
Security Latest
P
Proofpoint News Feed
阮一峰的网络日志
阮一峰的网络日志
K
KPMG report finds enterprise disconnect between AI and its ROI | CIO
T
Troy Hunt's Blog
T
Tailwind CSS Blog
Stack Overflow Blog
Stack Overflow Blog
云风的 BLOG
云风的 BLOG
A
About on SuperTechFans
The Last Watchdog
The Last Watchdog

蛮荆

如何获取更多的免费服务器 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 应用最佳实践 - 开篇 缓存策略和模式 Go 内存模型 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 数据类型:

参数由任意 ASCII 字符组成

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

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

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

💡 典型题目

前文中提到,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
}