数据结构与算法python版 MOOC 第八周

八、排序与查找-下

本系列博客基于“ (北京大学)数据结构与算法python版”慕课,课程在中国大学慕课bilibili上均可找到。

1. 内容

  1. 散列函数的定义和设计
  2. 散列冲突的解决方法
  3. 区块链技术

2. 课程代码

GitHub中下载

3. OJ作业

所有代码均可在github中下载

3.1 字符串中所有重排

题目内容:
   给定一个字符串s与待查找字符串p,请给出使得s[i: i+len ( p ) ]是p的一个字母重排的所有下标i。题目保证字符串p非空,且各字符串仅由小写字母构成

输入格式: 两行字符串,第一行为s,第二行为p
输出格式:所有满足条件的下标从小到大排列,以空格分隔输出。若无对应下标,则输出字符串"none"

输入样例:
abababa
ab
输出样例:
0 1 2 3 4 5

输入样例2:
a
b
输出样例2:
none

方法:通过一个变换,让几个字母任意组合的单词的结果都相同 方法: ascii码相加得到一个hash key。需要注意的是,直接相加会导致ac bb的key是相同的,所以给每个ascii码加上权重。最终函数为 ord(element)*(ord(element-96)) # 加上了24个字母自己的位置信息

def findAnagrams(s, p):
    # code here
    word_lenth = len(p)
    search_key = hash_key(p)  # 将需要搜索的字符转化为key
    record_index = []  # 记录s可以的index
    for i in range(0, len(s)-word_lenth+1):  # [0, len(s)-len(p)+1]
        current_key = hash_key(s[i:i+word_lenth])  # 将当前取的切片转化为key
        if current_key == search_key:
            record_index.append(i)

    if len(record_index):  # 如果找到了
        string = ' '.join(str(item) for item in record_index)
        print(string)
    else:  # 没找到
        print('none')
    return


def hash_key(word):
    key_sum = 0
    for element in word:  # 取出每一位字母
        key_sum += ord(element)*(ord(element)-ord('a'))
    return key_sum


s = input()
p = input()
findAnagrams(s, p)

3.2 列表出现最频繁的元素

题目内容:
   给定一个列表与数字K,按出现次数倒序输出列表中前K个出现最频繁的元素;若少于K个元素则返回所有元素。若有两个或以上的元素出现次数相等,按元素的值进行顺序输出,小的在前。

输入格式: 输入为两行。第一行为给定列表,以合法的Python表达式给出。第二行为数字K
输出格式:不多于K个数字,以空格分隔

输入样例:
[2,1,1,1,2,2,3]
2
输出样例:
1 2

方法:建立一个字典 存储 数字,数字出现次数。再把字典变成一个二维列表,对二维列表的第二维进行倒序排列,第二维是数字出现次数。再建立一个二维列表,将相同次数的数字放在一起,进行正序排序 输出时再把大家合并

代码

def topKFrequent(lst, k):
    # code here
    count_dict = {}
    for item in lst:
        if item in count_dict:  # 已经记录了该item
            count_dict[item] += 1
        else:  # 第一次出现
            count_dict[item] = 1
    count_list = []
    for key in count_dict.keys():  # 将字典变为二维数组
        count_list.append([key, count_dict[key]])

    count_list.sort(key=(lambda x: x[1]), reverse=True)  # 使用出现次数对数组进行排序

    string = []  # 输出序列
    # 将出现次数相同的数字切片,排序后加入到输出序列
    i = 0  # 索引
    same_num_list = []  # 数字表
    same_count = -1  # 次数
    while i < len(count_list):  # 当还没有搜索到最后一位
        if same_count != count_list[i][1]:  # 如果现在次数不相等
            if len(same_num_list):  # 且此时相同数字列表不为空(说明不是第一次)
                string.extend(sorted(same_num_list))  # 将数字表正序排列后加入到输出序列
            # 为空的话跳过
            same_num_list = []  # 清空列表
            same_count = count_list[i][1]  # 赋值新次数
        while i < len(count_list) and same_count == count_list[i][1]:  # 相等的话,都加入到相同数字表
            same_num_list.append(count_list[i][0])
            i = i+1
    string.extend(sorted(same_num_list))  # 将最后一组加入

    if k < len(string):  # 输出前k个
        joined_string = ' '.join(str(item) for item in string[:k])
    else:
        joined_string = ' '.join(str(item) for item in string)
    print(joined_string)
    return


lst = eval(input())
k = int(input())
topKFrequent(lst, k)

3.3 散列表

题目内容:
   给定一个指定大小N的散列表,并输入一系列数字:若找到空槽,则插入该数字,并返回槽位置;若该数字在散列表中存在,则直接输出其位置。
   注:使用下标增加的二次探测法解决散列冲突
   注2:散列表实际大小应确定为不小于用户输入N的最小质数

输入格式: 两行。第一行为用户指定散列表大小N。第二行为一系列数字,以空格分隔
输出格式:逐个输出对应数字在散列表中位置,以空格分隔。若该数字无法插入,则输出“-”

输入样例:
4
10 6 4 10 15
输出样例:
0 1 4 0 -

方法:由于题目规定了三列表大小 所以先求大于等于N的最小质数 方法就是逐步加1 判断是否是质数。
插入方法: 找到开始位置,当位置小于列表长度并且没有停止–继续循环: 如果该位置有数且等于要查找数,停止并返回位置 如果该位置没数,填入数并返回位置并停止
其余情况k=k+1 position = position+k*k
最后一个样例没有通过

代码:

def createHashTable(n):
    # 建立哈希表
    create_size = n  # 从n+1开始遍历
    stop = False
    while not stop:
        for divisor in range(2, create_size//2+1):  # 对于10,遍历 2,3,4,5
            if create_size % divisor == 0:  # 不是质数
                create_size = create_size+1
                break
        else:  # 每一位都不能除尽 所以是素数
            stop = True
    return [None]*create_size


def insertNumbers(table, nums):
    # code here
    t_len = len(table)  # 散列表长度
    insert_index_list = []  # 存储插入的位置
    for item in nums:  # 取出每一位数字
        position = item % t_len  # 最开始的位置
        k = 1  # skip
        stop = False
        record = []  # 记录查找了哪些位置了
        while not stop:
            if table[position] == None:  # 没有数
                table[position] = item
                insert_index_list.append(str(position))
                stop = True
            elif table[position] == item:  # 存在数并相等
                insert_index_list.append(str(position))
                stop = True
            else:  # 寻找下一个位置
                position = (item+k*k) % t_len
                if (position in record) or k >= t_len:  # 如果已经查找过该位置 说明找不到
                    stop = True
                    insert_index_list.append('-')
                k = k+1
                record.append(position)

    string = ' '.join(item for item in insert_index_list)
    print(string)
    return


n = int(input())  # 用户决定的散列表大小
nums = list(map(int, input().split()))
table = createHashTable(n)
insertNumbers(table, nums)
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值