编程珠玑第二章总结:

[0]:问题A:给出一个顺序文件,它最多包含40亿个随机排列的32位整数。找出一个不在文件中的32位整数。

分析:如果内存足够的话,可以采取第一章的位图排序法,以O(n)的效率就可以解决。
如果内存不足的话,但是有几个外部文件可以存储数据,那么就可以采用二分查找的思想来解决问题!!!这里的思路比较巧妙,它不是通常意义上的二分查找,但是思维模式很相似.我们可以通过扫描输入文件,将第一位是0的写入一个文件,将第一位是1的写入第二个文件,然后对比这两个文件的数据个数,可以肯定的是:[较少的一个文件必然含有缺少的整数],然后可以递归的处理问题,将这个文件看作是新的输入文件,并且记录丢失的整数相应的位数.用python描述的代码如下:
def find_lost(myarray):
    array = myarray
    lost = 0
    for bit in range(31,-1,-1):
        zero_array = []
        one_array = []
        checknum = 1<<bit
        for num in array:
            if(num&checknum == 0):
                zero_array.append(num)
            else:
                one_array.append(num)
        if(len(zero_array)<len(one_array)):
            array = zero_array
        else:
            array = one_array
            lost += checknum
    return lost

当然这个代码还可以进行优化,但是基本结构就是这样了.

问题B:二、类似字符串循环移位举例:比如abcdef 左移三位,则变成defabc条件限制:空间限制:可用内存为几十字节 时间限制:花费时间与n成比例

对于这个问题首先给出最简单的解法:逆转法,这个思路相当的巧妙:要处理的字符串时ab(a是需要移动的字符串),aR代表对a进行反转,那么可以这样处理,(aRbR)R就得到了所需要的结果

def myreverse(left,right,L):
    beg,end = left,right-1
    while(beg<end):
        L[beg],L[end] = L[end],L[beg]
        beg += 1
        end -= 1
def Reverse(i,s):
    myreverse(0,i,s)
    myreverse(i,len(s),s)
    myreverse(0,len(s),s)

然后还有稍微复杂一点的办法,但是效率稍高:

对数组中的元素进行步长为step的移位,比如a[0]<-a[step]<-a[2*step]…<-a[k*step](k*step<=n<(k+1)*step)<-a[0],这样就进行了一次循环移位,然后对a[1],a[2]…a[i-1]进行相同的操作,最后就得到了将前i个字符进行循环移位的结果.而且对比取逆法,只需要对元素操作一遍(交换的时候是操作2遍)
def myswap(i,L):
    def move(beg,step,L):
        i = beg+step
        t = L[beg]
        while(i<len(L)):
            L[i-step] = L[i]
            i += step
    L[i-step] = t
    for i in range(i):
        move(i,3,L)
    return L

问题C:、给出一个英语字典,找出所有变位词集。 比如age的变位词是age,aeg,eag,ega,gae,gea。

思路比较简单,可以对每一个单词进行一种标志,将所有变位词都转换到一个标准的标志比如bac,cab,acb->abc,然后通过对比标志来判断,假如只给了字典且不让预处理,那么就只能一个个的进行比较了.

def Get_Count(word):
    count = [0]*26
    for w in word:
        count[ord(w)-97] += 1
    ans = ''
    for key,item in enumerate(count):
        while(item!=0):
            ans += chr(key)
            item -= 1;
    return ans
def myquery(obj_word,word_dict):
    count = Get_Count(obj_word)
    for words in word_dict:
        if(count == Get_Count(words)):
            print(words)

假如可以进行预处理,那么就将字典处理成一个开放散列结构,将相同的标志收集到一块来:

def preprocess(word_dict):
    New_dict = {}
    for words in word_dict:
        count = Get_Count(words)
        if(New_dict.get(count)==None):
            New_dict[count] = [words]
        else:
            New_dict[count].append(words)
    return New_dict
def new_query(obj_word,new_dict):
    return new_dict[Get_Count(obj_word)]

问题2,如何在4300 000 000个32位整数里面找出一个至少出现2次的整数,这个和问题A的思路基本相似,只需要将二分的策略改为含有数据较多的那一个区间,下面简单证明一下:

首先知道当前输入里面一定有重复的数字,不妨假设两个文件A,B分别包含了 x,y,x+y=Nx>y .因为 N>2k=>x>N2k ,A没有重复数据的情况下最多应该包含了所有 2k1<N2 种数字,那么 x>N2 是不合理的。因此A一定含有重复数据。

问题8:给定一个n元实数集合,一个实数t和一个整数k,如何快速确定是否存在一个k元子集,其元素之和不超过t.

[1]:直接排序,然后找到最小的k元集合。
def fast_find_k(array,k,t):
    array.sort()
    sum_min_set = 0
    for item in array[0:k]:
        sum_min_set += item
    return sum_min_set <= t
print(fast_find_k([9,8,7,6,5,4,3,2,1],3,5))

[2]:采用快速选择算法,找到一个第i小的元素需要花费的时间为 O(n) ,所以选择k元最小集合只需要 O(kn)

[3]:堆排序算法: O(n)+kO(logn), k .更快速的思路是应该用Topk最小堆的算法构造。

问题9:这就是一个简单的数学题,不妨假设两种方式的时间消耗为 kO(n),O(nlogn)+kO(logn) ,分离变量计算得 k>=nlognnlogn

问题10,用水去算体积。。。。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值