哈希算法python

文章目录

    • 一、两个数的和
      • 1、双指针算法
      • 2、哈希算法
    • 二、单词模式匹配
    • 三、猜词游戏
    • 四、神奇的词根
      • 1、暴力解法
      • 2、哈希查找

该篇学习笔记来自于《你也能看得懂的python算法书》
哈希算法又称散列表函数算法,是一种查找算法,简单来说,就是把一些复杂的数据,通过某种函数的映射关系,映射成更加易于查找的方式。常见的数据查找算法:顺序查找,二分查找,深度优先遍历,广度优先遍历,哈希查找。

一、两个数的和

问题描述:数学课上,老师出了一道题目,要求在给定的一些数字中找出两个数,使得它们的和为N,前提是这些数据中保证有答案,并且只有一个答案。例如给定5个数字:3、4、5、7、10,从中选择两个数使它们的和为11,可以选择4和7,这个问题该如何解决呢?

1、双指针算法

def twosum(num,target):
    res=[]
    newsum=num[:]
    newsum.sort()
    left=0
    right=len(newsum)-1
    while left<right:
        if newsum[left]+newsum[right]==target:
            for i in range(len(num)):
                if newsum[left]==num[i]:#newsum是有序数组,num是原始数组
                    res.append(i)#将下标加入结果集
                    break
                for i in range(len(num)-1,-1,-1):
                    if newsum[right]==num[i]:
                        res.append(i)#将下标加入结果集
                        break
            res.sort()
            break
        elif newsum[left]+newsum[right]>target:
            right-=1
        elif newsum[left]+newsum[right]<target:
            left+=1
    return(res[0]+1,res[1]+1)
print(twosum([3,4,5,7,10],11))
#输出:(2,4)

2、哈希算法

def twosum(num,target):
    dict={}
    for i in range(len(num)):
        m=num[i]
        if target-m in dict:
            return(dict[target-m]+1,i+1)
        dict[m]=i
print(twosum([3,4,5,7,10],11))
#输出:(2,4)

在第一种算法的基础上,我们研究更加高效的算法,哈希函数是怎样解决这个问题的。

  • 首先,考虑在双指针排序解法中,时间都浪费在哪里。
  1. 双指针算法的前提是数据有序,接着为了寻找答案,左右指针在不停地移动
  2. 当左右指针发现答案后,由于需要返回原始数据的位置,还需要去原始数组中寻找这两个数据的位置
  • 其次,为了使用哈希算法,我们需要先建立一个字典,用于存放数据的和下标的对应关系。
  1. 字典是一个键值对的集合
  2. 使用统一的哈希函数把数据对存储到字典中,再使用统一的哈希函数从字典中把数据取出来,从而达到常数级别的查询速度

二、单词模式匹配

给定两个字符串,一个是单词模式字符串,另一个是目标字符串,检查目标字符串中单词出现的规律是否符合单词模式字符串中的规律。
注意:映射关系分为一对一关系,一对多关系和多对多关系。
寻找映射关系的问题本质上也是查找问题,既然是查找问题,考虑使用哈希算法。

def wordpattern(wordpattern,input):
    word=input.split(' ')
    if len(word)!=len(wordpattern):#长度不等
        return False
    hash={}#记录模式字符串和目标字符串的对应关系
    used={}#记录目前已经使用过的字符串
    for i in range(len(wordpattern)):
        if wordpattern[i] in hash:#第二次出现该映射关系,检查是否一致
            if hash[wordpattern[i]]!=word[i]:
                return False
        else:#首次出现映射关系
            if word[i] in used:#检查该单词是否使用过
                return False
            hash[wordpattern[i]]=word[i]#若首次出现,加入哈希表
            used[word[i]]=True
    return True
print(wordpattern([1,2,1,2],"a b a a"))
#输出:False

三、猜词游戏

问题描述:小明在和小朋友玩猜数字游戏,这个游戏的玩法是这样的。一个人写下数字让另外一个人猜,当每次答题方猜完之后,出题方会给答题方一个提示,告诉他刚才有多少位数字和确切位置都猜对了(称为"Bulls",公牛),还有多少位数字猜对了但位置不对(称为”Cows",奶牛)。答题方将会根据出题方的提示继续猜,直到猜出秘密数字位置。
注意:

  1. 秘密数字和朋友猜测的的数字都可能含有重复数字
  2. 秘密数字中的某一位和猜测中的某一位匹配,该数就不能和其它数字匹配了
def gethint(secret,guess):#参数类型是字符串
    secret_list={}
    guess_list={}
    A=0
    B=0
    for i in range(len(secret)):
        if secret[i]==guess[i]:
            A+=1
        else:
            if secret[i] in secret_list:
                secret_list[secret[i]]=secret_list[secret[i]]+1
            else:
                secret_list[secret[i]]=1
            if guess[i] in guess_list:
                guess_list[guess[i]]=guess_list[guess[i]]+1
            else:
                guess_list[guess[i]]=1
    for digt in secret_list:#按照出现的字符依此查找
        if digt in guess_list:
            B+=min(secret_list[digt],guess_list[digt])
    return str(A)+"A"+str(B)+"B"#字符串拼接
print(gethint("2019","9021"))
#输出:1A3B

四、神奇的词根

问题描述:英语课上,英语老师为了让同学们掌握常见的词根来帮助理解和记忆单词,发明了一个游戏。这个游戏的玩法是这样的,给定一个有许多词根组成的字典和一个句子,你需要将句子中的所有继承词用词跟替换掉。如果继承词中有许多形成它的词语,则用最短的词根替换它。例如,字典为[“cat”,“bat”,“rat”],句子为”The cattle was ratted by the battery",经过替换,输出句子为“the cat was rat by the bat"。试写一个程序来解决这个问题。

1、暴力解法

该代码虽然能够解决问,但效率太低,对于每一个词根,需要在所有单词中截取相应位数的子字符串,加入词根的量很多或者单词的数量很多,双重循环的效率很低。在这个过程中,可以把用单词去匹配词根的过程通过哈希来优化。

def replacewords(dict,sentence):
    sentence=sentence.split()
    for item in dict:
        for i in range(len(sentence)):
            n=len(item)
            if item==sentence[i][:n]:
                sentence[i]=item
    return ' '.join(sentence)
print(replacewords(["cat","bat","rat"],"the cattle was rattled by the battery"))

2、哈希查找

  • 每个词根的首字母为键,把每一个词放到该键对应一个的值里,这里的值是一个集合,同时记录下集合里最大词根的长度
  • 使用enumerate()函数来遍历句子,它会把索引放到第一个变量,把元素放到第二个变量。
  • Python中通过Key访问字典,当Key不存在时,会引发‘KeyError’异常。为了避免这种情况的发生,可以使用collections类中的defaultdict()方法来为字典提供默认值。
import collections
def replacewords(dict,sentence):
    d=collections.defaultdict(set)
    s=collections.defaultdict(int)
    sentence=sentence.split()#句子的列表
    for w in dict:
        print (w[0])#词根的首字母
        d[w[0]].add(w)#添加到集合中,词根的首字母作为键,词跟为值(集合,可以多个)存入
        s[w[0]]=max(s[w[0]],len(w))#所有词根中最大的长度
    for i,w in enumerate(sentence):
        for j in range(s[w[0]]):#取相关词根的最大长度
            if w[:j+1] in d[w[0]]:#判断所找单词是否在词根集合里
                sentence[i]=w[:j+1]
                break
    return ' '.join(sentence)
print(replacewords(["cat","bat","rat"],"the cattle was rattled by the battery"))

执行结果如下:
哈希算法python_第1张图片

你可能感兴趣的:(算法)