编程珠玑第二章总结:

来源:互联网 发布:淘宝的网商银行贷款吗 编辑:程序博客网 时间:2024/05/18 17:44

[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 -= 1def 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 ansdef 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_dictdef 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 <= tprint(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,用水去算体积。。。。

0 0