编程珠玑第二章读书笔记

第二章 啊哈!算法 

 

2.1 三个问题

A 一个最多40亿个随机排列的32位整数文件,找出一个不在文件中的32位整数。足够内存下如何解决?有几个外部临时文件可用,仅几百字节内存,如何解决?

B 将一个n元一维向量x向左旋转i个位置,abcdefgh旋转为defghabc,仅使用数十个额外字节的存储空间。

C 一个英语词典中,找出所有变位词组合,stop tops pots

2.2二分搜索

初始条件:已知一个对象存在于一个给定的范围内,一次探测可得到对象是否高于,等于,低于当前的位置。

过程:重复探测中点,直到找到或范围为空。

问题A解法:

对每个整数的32位进行二分搜索:

<1>第一趟读取40亿个数,并将第一位以0开头的写入一个文件,以1开头的写入另一个文件。有一个文件包含20亿个整数,一个文件包含整数数量小于20亿。

<2>对上一步处理得到的总数小于20亿的文件进行处理,探测第二位,为0的保存在一个文件,为1的保存在另一个文件。

第一趟读取n个整数,第二趟读取n/2个整数,以此类推,总运行时间正比于nlogn。

2.3基本操作的威力

对于问题B,有以下几种解法:

解1:将一维向量x前i位存入临时数组,剩下n-i位向前移动i个位置,然后将前i位放入剩余位置。

问题:需要大量额外空间

解2:定义一个函数,将一个一维数组x向左旋转一位,重复调用i次。

问题:巨大时间消耗

解3:x[0]保存在临时变量t中,x[i]移动到x[0],x[2i]移动到x[i],以此类推。然后将x[0]从临时变量取出放入。如果所有的元素都被移动则结束,否则对x[1]重复。

解4:将x分为a b两段,x左移即相当于交换ab两段位置,考虑到a长度为i,b长度为n- i,a b长度可能不等,将b分为bl br,br长度为i。

将问题看作把数组ab转为ba,通过reverse实现,先对a reverse到a'b,然后对b reverse a'b',然后再对整体reverse即可得到ba。

按照以上reverse的思路,代码实现如下:

def lefti(x,i):
    x[0:i] = list(reversed(x[0:i]))
    x[i:] = list(reversed(x[i:]))
    x = list(reversed(x))
    return x

x = ['a','b','c','d','e','f','g','h']
print(lefti(x,3))

2.4排序

问题C的解法:

1.考虑单词中所有字母的所有排列方法(使用完全相同的字母组合,但位置顺序不同,如果一个单词长为i,将有i!中方法)

2.为每个单词创造一个标识,使得变位词具有相同的标识:将单词中字母按照字母表顺序排列(deposit dopiest的标识均为deposit)然后将所有单词按照其标识进行排序,将具有相同标识的单词即变位词集中在一起。

2.5原理

排序:

<1>产生有序的输出。

<2>另一个程序(如二分搜索)的前期准备工作。

<3>把字母按照字母表顺序排列作为单词的标识。

二分搜索:

<1>在有序表查找元素。

<2>内存排序或磁盘排序。

缺陷:整个表必须已知并且事先排好序。

标识:

标识使得一类中的每一项都具有相同的标识。

比如问题C中的单词标识,以及用来识别读音相同但拼写不同的名字的soundex方法。

2.6习题

1.考虑查找给定输入单词的所有变位词问题。仅给定单词和字典的情况下,如何解决?

仅给定单词和字典,无法进行预处理,只能遍历词典中的单词,计算每个单词的标识(按字母字典顺序排列),然后与给定单词的标识比较。

5.向量旋转函数将向量ab变为ba。如何将向量abc变为cba?(交换非相邻内存块问题进行了建模)

题解关键:(a’b’c’)’=cba 分别对abc每个部分求逆,然后对整个字符串求逆,得到的结果就是cba

代码:

def abc_to_cba(a,b,c):
    reversed_a = "".join(reversed(a))
    reversed_b = "".join(reversed(b))
    reversed_c = "".join(reversed(c))
    print(reversed_a)
    print(reversed_b)
    print(reversed_c)
    print(type(reversed_a))
    mystr = reversed_a+reversed_b+reversed_c
    newstr = "".join(reversed(mystr))
    print(newstr)
    return newstr

结果:

注意⚠️:

python中字符串翻转方式:

<1>str[::-1]

<2>"".join(reversed(str))

6.一个“电话号码簿”辅助程序,可以使用按键在号码薄中查找电话。查找Mike Lesk,可以按"LESK*M*"即5375*6*实现。但不同的名字可能具有相同的按键编码。实现一个以名字的按键编码为参数,返回所有可能的匹配名字的函数。

将按键编码作为名字的标识,对号码簿中的所有名字按照按键编码进行标识,并按照按键编码进行排序。

 

 

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值