Hash Exercise 21.11.27

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 单词模式匹配

规则:如果单词模式字符串和目标字符串只存在一对一的对应关系,不存在一对多和多对多的对应关系,就可以说明两个字符串匹配成功

要点,除一对多,多对一的情况

  1. 模式字符串中的每个字符只能对应目标字符串一个单词的问题。

  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原题

205.同构字符串

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 猜词游戏

299.猜数字游戏

游戏规则:一个人写下几个数字让另外一个人猜,当每次答题方猜完之后,出题方会给答题方一个提示,告诉他刚才的猜测中有多少位数字和确切位置都猜对了(Bulls),还有多少位数字猜对了但是位置不对(Cows),答题方根据出题方的提示继续猜,知道猜出秘密数字为止。

例子:secret2018,guess8021

0数字和位置都对了,A表示公牛

128数字都对了,位置全不对,B表示奶牛

所以给出提示:1A3B

练习:secret1123,guess9111 (1A1B)

问题求解

本题只需判断一次,没有那么复杂

对secret或guess一次遍历,反正长度一样

  1. 先判断同位置上是否相等,如果相等,则公牛加一,并跳过Hash记录
  2. 如果不相等,就记录在两个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 神奇的词根

648.单词替换

  • 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) 字典的大小

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值