Day01 and Day02 理论学习
什么是哈希桶?就是键对应的那个链表,生活中把东西放入桶中是有顺序的,因此用桶来比喻有顺序的链表
问题1 经典的两数之和
1、双指针
需要排序
2、哈希表
双指针解法的缺点,排序之后还要找到原始数据这两个数字的位置
哈希表解法:一边记录数字,一边寻找它的另一半
class Solution(object):
def twoSum(self, nums, target):
dic = {}
for i in range(len(nums)):
m = nums[i]
if target - m in dic:
return (i + 1, dic[target - m] + 1)
dic[nums[i]] = i
A = Solution()
print(A.twoSum([2,3,4,6], 7))
问题2 单词模式匹配
规则:如果单词模式字符串和目标字符串只存在一对一的对应关系,不存在一对多和多对多的对应关系,就可以说明两个字符串匹配成功
要点,除一对多,多对一的情况
-
模式字符串中的每个字符只能对应目标字符串一个单词的问题。
-
当模式字符串中的某个字符第一次出现时,还需要判断这个单词是否已经和其他的模式字符绑定。
class Solution(object):
def wordPattern(self, wordPattern, word):
# 如果长度不一致直接False
if len(wordPattern) != len(word):
return False
# 单词的哈希表,防止一个单词对应多个模式
wordHash = {}
# 模式的哈希表,防止一个模式对应多个单词
patternHash = {}
# 对单词或模式遍历都是一样的,因为它们长度已经相等
for i in range(len(word)):
# 如果单词出现过,比较模式
if word[i] in wordHash:
if wordPattern[i] != wordHash[word[i]]:
return False
else:
# 如果单词没有出现过,但是却已经用过它对应的模式
if wordPattern[i] in patternHash:
return False
wordHash[word[i]] = wordPattern[i]
patternHash[wordPattern[i]] = True # 或者 word[i]
return True
A = Solution()
print(A.wordPattern([1, 3, 2, 2], ["apple", "pear", "banana", "banana"]))
print(A.wordPattern([1, 1, 2, 2], ["apple", "apple", "banana", "banana"]))
print(A.wordPattern([1, 1, 1, 1], ["apple", "apple", "banana", "banana"]))
print(A.wordPattern([1, 1, 2], ["apple", "apple", "banana", "banana"]))
True
True
False
False
LeetCode原题
class Solution(object):
def isIsomorphic(self, s, t):
"""
:type s: str
:type t: str
:rtype: bool
"""
if len(s) != len(t):
return False
sHash = {}
tHash = {}
for i in range(len(s)):
# 如果s[i]在sHash中出现了
if s[i] in sHash:
if t[i] != sHash[s[i]]:
return False
else:
# 如果s[i]没有出现,它的模式却用过了
if t[i] in tHash:
return False
sHash[s[i]] = t[i]
tHash[t[i]] = True
return True
问题3 猜词游戏
游戏规则:一个人写下几个数字让另外一个人猜,当每次答题方猜完之后,出题方会给答题方一个提示,告诉他刚才的猜测中有多少位数字和确切位置都猜对了(Bulls),还有多少位数字猜对了但是位置不对(Cows),答题方根据出题方的提示继续猜,知道猜出秘密数字为止。
例子:secret2018,guess8021
0数字和位置都对了,A表示公牛
128数字都对了,位置全不对,B表示奶牛
所以给出提示:1A3B
练习:secret1123,guess9111 (1A1B)
问题求解
本题只需判断一次,没有那么复杂
对secret或guess一次遍历,反正长度一样
- 先判断同位置上是否相等,如果相等,则公牛加一,并跳过Hash记录
- 如果不相等,就记录在两个Hash表中
再对字典遍历,如果两个都有出现,取最小值,并将记录加到奶牛中
class Solution(object):
def getHint(self, secret, guess):
bulls = 0 # 公牛的个数
cows = 0 # 奶牛的个数
secretDict = {}
guessDict = {}
# 查找公牛直接一一对应
for i in range(len(secret)):
if secret[i] == guess[i]:
bulls = bulls + 1
else:
if secret[i] in secretDict:
secretDict[secret[i]] += 1
else:
secretDict[secret[i]] = 1
if guess[i] in guessDict:
guessDict[guess[i]] += 1
else:
guessDict[guess[i]] = 1
for item in secretDict:
if item in guessDict:
cows = cows + min(secretDict[item], guessDict[item])
return str(bulls) + 'A' + str(cows) + "B"
A = Solution()
print(A.getHint("2018", "8021"))
print(A.getHint("1123", "9111"))
print(A.getHint("1", "0"))
print(A.getHint("0", "0"))
1A3B
1A1B
0A0B
1A0B
问题4 神奇的词根
- 1 <= dictionary.length <= 1000
- 1 <= dictionary[i].length <= 100
- dictionary[i] 仅由小写字母组成。
- sentence 中单词的总量在范围 [1, 1000] 内。
- sentence 中每个单词的长度在范围 [1, 1000] 内。
例子:词根 [“cat”, “bat”, “rat”]
句子"the cattle was rattled by the battery"
替换"the cat was rat by the bat"
暴力解法
对字典里的每一个词根,都要去看看每个单词是否能匹配呢
class Solution(object):
def replaceWords(self, dictionary, sentence):
words = sentence.split(" ")
for root in dictionary:
for i in range(len(words)):
if root == words[i][:len(root)]:
words[i] = root
return ' '.join(words)
执行用时:124 ms, 在所有 Python 提交中击败了60.00%的用户
内存消耗:20.9 MB, 在所有 Python 提交中击败了85.71%的用户
通过测试用例:126 / 126
因为数据量比较小,所以没有超时
Hash解法
该解法用到了hash加list的结构
d以26个字母为键,把出现的词根放进首字母键中,因此会有列表出现
{‘c’: [‘catt’, ‘cat’], ‘b’: [‘bat’], ‘r’: [‘rat’]}
s也以26个字母为键,把出现的词根的长度放进对应的键中,并记录最大值
{‘c’: 4, ‘b’: 3, ‘r’: 3}
然后以最大长度为上限遍历,如果该单词的前n个字母出现在d相应的键的列表中,就替换并退出,因为词根重复时只要最短值
class Solution(object):
def replaceWords(self, dictionary, sentence):
words = sentence.split(" ")
d = {}
s = {}
for w in dictionary:
if w[0] in d:
d[w[0]].append(w)
else:
d[w[0]] = []
d[w[0]].append(w)
if w[0] in s:
s[w[0]] = max(s[w[0]], len(w))
else:
s[w[0]] = len(w)
# return d, s
# enumerate(words) 同时获得words这个列表的索引和值
for i, w in enumerate(words):
if w[0] in s :
for j in range(s[w[0]]):
if words[i][:j + 1] in d[w[0]]:
words[i] = w[:j + 1]
break
return " ".join(words)
A = Solution()
print(A.replaceWords(["cat", "bat", "rat"],
"the cattle was rattled by the battery"))
print(A.replaceWords(["a", "b", "c"],
"aadsfasf absbs bbab cadsfafs"))
print(A.replaceWords(["a", "aa", "aaa", "aaaa"],
"a aa a aaaa aaa aaa aaa aaaaaa bbb baba ababa"))
print(A.replaceWords(["catt", "cat", "bat", "rat"],
"the cattle was rattled by the battery"))
print(A.replaceWords(["ac", "ab"],
"it is abnormal that this solution is accepted"))
the cat was rat by the bat
a a b c
a a a a a a a a bbb baba a
the cat was rat by the bat
it is ab that this solution is ac
感觉没有快多少
执行用时:88 ms, 在所有 Python 提交中击败了71.43%的用户
内存消耗:20.9 MB, 在所有 Python 提交中击败了91.43%的用户
时间复杂度
O(N) 只算遍历句子的长度,字典的长度比句子单词个数少,虽然是两次遍历但是简化为句子的遍历,而Hash表的查找是常数操作
空间复杂度
O(N) 字典的大小