LeetCode刷题1:第三周
目录
相关系列笔记:
LeetCode刷题:前言
LeetCode刷题1:第一周
LeetCode刷题1:第二周
LeetCode刷题1:第三周
LeetCode刷题1:第四周
LeetCode刷题1:第五周
LeetCode刷题1:第六周
LeetCode刷题1:第七周
前言
week3 Topic:哈希表,题目列表如下
(1) 202.快乐数
(2) 217.存在重复元素
(3) 49.字母异位词分组
(4) 36.有效的数独
(5) 347.前K个高频元素
知识点
散列表(也叫哈希表) 是一种数据结构,其数据元素的地址或索引值由散列函数生成。 这使得访问数据的速度更快,因为索引值是数据值的关键字。 换句话说,哈希表存储键值对,但键是通过哈希函数生成的。
因此,数据元素的搜索和插入函数变得更快,因为键值本身成为存储数据的数组的索引。
在Python中,字典数据类型表示哈希表的实现。字典中的键满足以下要求。
• 字典的键是可散列的,即通过散列函数生成该散列函数,该散列函数为提供给散列函数的每个唯一值生成唯一结果。
• 字典中数据元素的顺序不固定。
哈希函数是一个可以将任意长度的数据块映射到固定长度的值,这个步骤称为hash,也就是散列。
hash 函数有三个主要的特征:
1. 计算迅速:计算一个数据块的hash值非常快
2. 确定性:相同用字符串会产生相同的hash值
3. 结果固定长度:不管输入的是,一个字节还是十个字节,或者上万个字节,结果总是预先确定的长度。
另一个特征在hash函数中非常普遍,即他们是单方向的:通过函数实现后,原始数据丢失了,我们可以通过字符串得到一个hash值,但不能通过一个hash也就是散列得到原始的字符串(因为有对数据降维的方法会造成数据的丢失)。这种特性并不是对所有hash函数的强制性规定,但是当需要加密安全时,这种性质还是挺好用的。
一些比较受欢迎的算法包括:MD5、SHA-1、SHA-2,NTLM。
所以可通过使用下面的字典数据类型来看到哈希表的实现。
在字典中访问值
要访问字典元素,可以使用熟悉的方括号 [] 来获取它的值。
# Declare a dictionary
dict = {'Name': 'maxsu', 'Age': 27, 'Class': 'First'}
# Accessing the dictionary with its key
print ("dict['Name']: ", dict['Name'])
print ("dict['Age']: ", dict['Age'])
执行上面示例代码,得到以下结果
dict['Name']: maxsu
dict['Age']: 27
Shell
更新字典元素
可以通过添加新条目或键值对,修改现有条目或删除现有条目来更新字典,如简单示例中所示 -
# Declare a dictionary
dict = {'Name': 'Maxsu', 'Age': 26, 'Class': 'First'}
dict['Age'] = 8; # update existing entry
dict['School'] = "第一中学"; # Add new entry
print ("dict['Age']: ", dict['Age'])
print ("dict['School']: ", dict['School'])
执行上面示例代码,得到以下结果
dict['Age']: 8
dict['School']: 第一中学
Shell
删除字典元素
可以删除单个字典元素,也可以清除字典的全部内容。 也可以在一个操作中删除整个字典。 要显式删除整个字典,只需使用del语句。 参考以下代码 :
dict = {'Name': 'Maxsu', 'Age': 26, 'Class': 'First'}
del dict['Name']; # remove entry with key 'Name'
dict.clear(); # remove all entries in dict
del dict ; # delete entire dictionary
print ("dict['Age']: ", dict['Age'])
print ("dict['School']: ", dict['School'])
Python
请注意,由于在执行del语句之后,字典不再存在之后会引发异常。
LeetCode例题
202. 快乐数
编写一个算法来判断一个数 n 是不是快乐数。
「快乐数」定义为:对于一个正整数,每一次将该数替换为它每个位置上的数字的平方和,然后重复这个过程直到这个数变为 1,也可能是 无限循环 但始终变不到 1。如果 可以变为 1,那么这个数就是快乐数。
如果 n 是快乐数就返回 True ;不是,则返回 False 。
示例:
输入:19
输出:true
解释:
1^2 + 9^2 = 82
8^2 + 2^2 = 68
6^2 + 8^2 = 100
1^2 + 0^2 + 0^2 = 1
实现:
class Solution:
def isHappy(self, n: int) -> bool:
already = set()
while n != 1:
if n in already:
return False
already.add(n)
n = sum([int(x) * int(x) for x in str(n)])
return True
217. 存在重复元素
给定一个整数数组,判断是否存在重复元素。
如果任意一值在数组中出现至少两次,函数返回 true 。如果数组中每个元素都不相同,则返回 false 。
示例 1:
输入: [1,2,3,1]
输出: true
示例 2:
输入: [1,2,3,4]
输出: false
示例 3:
输入: [1,1,1,3,3,4,3,2,4,2]
输出: true
实现:
首先set(nums),集合会直接删除重复元素
然后判断集合是否和列表等长,等长返回False 不等长说明有重复数,返回True
class Solution:
def containsDuplicate(self, nums: List[int]) -> bool:
# set(nums)直接删除重复元素
# 判断集合是否和列表等长
return not len(nums) == len(set(nums))
49. 字母异位词分组
给定一个字符串数组,将字母异位词组合在一起。字母异位词指字母相同,但排列不同的字符串。
示例:
输入: [“eat”, “tea”, “tan”, “ate”, “nat”, “bat”]
输出:
[
[“ate”,“eat”,“tea”],
[“nat”,“tan”],
[“bat”]
]
实现:
class Solution:
def groupAnagrams(self, strs: List[str]) -> List[List[str]]:
dic = {}
res = []
# 把每个字符串分类
# 排序字符串变成列表再转成字符串
for word in strs:
dic.setdefault(str(sorted(word)),[]).append(word)
for val in dic.values():
res.append(val)
return res
36. 有效的数独
判断一个 9x9 的数独是否有效。只需要根据以下规则,验证已经填入的数字是否有效即可。
1. 数字 1-9 在每一行只能出现一次。
2. 数字 1-9 在每一列只能出现一次。
3. 数字 1-9 在每一个以粗实线分隔的 3x3 宫内只能出现一次。
上图是一个部分填充的有效的数独。
数独部分空格内已填入了数字,空白格用 ‘.’ 表示。
示例 1:
输入:
[
[“5”,“3”,".",".",“7”,".",".",".","."],
[“6”,".",".",“1”,“9”,“5”,".",".","."],
[".",“9”,“8”,".",".",".",".",“6”,"."],
[“8”,".",".",".",“6”,".",".",".",“3”],
[“4”,".",".",“8”,".",“3”,".",".",“1”],
[“7”,".",".",".",“2”,".",".",".",“6”],
[".",“6”,".",".",".",".",“2”,“8”,"."],
[".",".",".",“4”,“1”,“9”,".",".",“5”],
[".",".",".",".",“8”,".",".",“7”,“9”]
]
输出: true
示例 2:
输入:
[
[“8”,“3”,".",".",“7”,".",".",".","."],
[“6”,".",".",“1”,“9”,“5”,".",".","."],
[".",“9”,“8”,".",".",".",".",“6”,"."],
[“8”,".",".",".",“6”,".",".",".",“3”],
[“4”,".",".",“8”,".",“3”,".",".",“1”],
[“7”,".",".",".",“2”,".",".",".",“6”],
[".",“6”,".",".",".",".",“2”,“8”,"."],
[".",".",".",“4”,“1”,“9”,".",".",“5”],
[".",".",".",".",“8”,".",".",“7”,“9”]
]
输出: false
解释: 除了第一行的第一个数字从 5 改为 8 以外,空格内其他数字均与 示例1 相同。
但由于位于左上角的 3x3 宫内有两个 8 存在, 因此这个数独是无效的。
实现:
class Solution:
def isValidSudoku(self, board: List[List[str]]) -> bool:
def isvaild9(lyst):
nums = list(filter(lambda x:x != '.', lyst))
return len(set(nums)) == len(nums)
for row in board:# 行
if not isvaild9(row):
return False
for column in zip(*board):# 列
if not isvaild9(column):
return False
for row in range(3):# 3*3宫格
for column in range(3):
tmp = [board[i][j] for i in range(row*3, row*3+3) for j in range(column*3, column*3+3)]
if not isvaild9(tmp):
return False
return True
347. 前 K 个高频元素
给定一个非空的整数数组,返回其中出现频率前 k 高的元素。
示例 1:
输入: nums = [1,1,1,2,2,3], k = 2
输出: [1,2]
示例 2:
输入: nums = [1], k = 1
输出: [1]
提示:
• 你可以假设给定的 k 总是合理的,且 1 ≤ k ≤ 数组中不相同的元素的个数。
• 你的算法的时间复杂度必须优于 O(n log n) , n 是数组的大小。
• 题目数据保证答案唯一,换句话说,数组中前 k 个高频元素的集合是唯一的。
• 你可以按任意顺序返回答案。
实现:
直接counter,然后对生成的字典排序取前k个即可,时间复杂度为nlogn
class Solution:
def topKFrequent(self, nums: List[int], k: int) -> List[int]:
# counter,对生成的字典排序取前k个
dic = Counter(nums)
res = sorted(dic.items(), key=lambda item:item[1], reverse=True)
return list(map(lambda x:x[0], res))[:k]