编程珠玑第8章总结

来源:互联网 发布:淘宝进口零食推荐 知乎 编辑:程序博客网 时间:2024/06/07 19:38

第八章主要讲了几个基本算法设计技术,引入了一个累加数组的思路,这个思路很有意思。

4 这个题目从数学上我是不会做的

E(max)=limNN0p(max)maxdmaxN.....(1)

P(maxx)=x0p(max)dmax=?......(2)

中间这个问号就是关键,应该可以从这里导出关于最大值的分布函数,但是思考了半天不得其解。经过程序模拟:

def max_subvec(array):    max_here = 0    max_sum = 0    for it in array:        max_here = max(0,max_here+it)        max_sum = max(max_here,max_sum)    return max_sumdef simulate():    import random    sum = 0    for i in range(5000):        case_vec = [random.uniform(-1,1) for i in range(1000)]        sum += max_subvec(case_vec)    return sum/5000print(simulate())

最大值大约是22.3左右….这个数字很奇怪,不知道怎么来的。

我认为通过反证法就可以证明,假设有一个数远远大于其它所正数输入的和, 或者是一个很小的负数,那么如果不检测这个输入就没有办法确定是否要把这个输入考虑进来,那么就没有办法得到正确得答案。

10

首先如果是查找接近0的子向量,那么存在O(NlogN)的算法。解决方法很巧妙,它利用这样一个事实:寻找一段和接近0的子向量,就是在寻找两个非常接近的累加数组的元素!这样就把问题成功转换了。这样问题就回到寻找相似元素的思路上。假如是寻找完全相同的元素那么利用hash散列可以以O(N)的时间界求解,如果是寻找最接近,那么就可以采取排序的办法来解决,对一个有序的序列进行遍历,观测两两相邻的元素那个最接近即可。代码如下:

def zero_subvec(array):    #defensive coding,test the input    n = len(array)    if n <2:return array[0]    #compute accumulate array    cumarr = [(0,-1)]    last = 0    for i,each in enumerate(array):        cumarr.append((last+each,i))        last +=each    cumarr.sort(key = lambda t:t[0])    print(cumarr)    #test the near pair    min_sub = (cumarr[1][1],cumarr[0][1],cumarr[1][0]-cumarr[0][0])    for i in range(0,len(cumarr)-1):        if cumarr[i+1][0]-cumarr[i][0] < min_sub[2]:            min_sub = (cumarr[i+1][1],cumarr[i][1],cumarr[i+1][0]-cumarr[i][0])    if min_sub[0]<min_sub[1]:        print('[',min_sub[0]+1,',',min_sub[1],']','-----',-min_sub[2])    else:print('[',min_sub[1]+1,',',min_sub[0],']',min_sub[2])

这里有一个细节需要注意:我们在采用累加数组计算的时候,一定要添加一个假想的累加元素,即0之前的元素和,为什么?因为这样才能用累加数组完整的表示jk=ia[k].....(3),否则i=0的情况没法表示。当然我们也可以在程序里特殊处理,计算第一个元素的绝对值作为初始值,然后再两两作差比较。

如果要找到一个最接近t的元素怎么办,这个问题看似和原来的一样,实际上是没办法用O(NlogN)的算法来处理的,最坏的情况应该是N^2.假设子向量是x,注意到:利用累加数组之间的差值表示实际上得到的是d=|x|,使|xt|,|d1|,这样一来就没有办法利用排序进行优化了,当然t=0时由于两者没有区别,所以可以不去考虑正负。

最后,如果所有输入都是正数的情况下,求最接近实数t的子向量,这是可以利用累加数组进行优化的,因为

x=|x|,cumarr[i]....cumarr[n]x,|xt|,...
,因此可以利用这个条件排除掉一些不必要的搜索,比如当
|xt|00,
,这里还可以利用二分查找获得首次大于0的值,如果不存在则最后一个¥|xt|,这样每一次搜查时logN,一共进行N次二分查找再加上排序的消耗,最后也是NlogN的复杂度。

12

这个是可以将时间从O(N*N)推向O(N)的,思路还是需要引入一个记录数组来解决。关键是考虑这样一个事实,一次输入的参数l,u,v,x[l]….x[u]都是加上同一个参数,可以把它们当作一个整体对待。伪代码如下:

for each case with l,u,v:    cum[u]+=v    cum[l-1]-=vx[n] = cum[n]for i from n-1 to 0:    x[i] = cum[i]+x[i+1]

可以很容易证明其正确性,首先初始情况x[n]的值显然是正确,其次对于任意一个i,x[i]=ik=ncum[k]......(4),这很容易理解:前面的区间如果将i包含(l<=i<=u),那么在这个区间里面的v就应该加上,而不应该加上v的元素位置必然在l的后面,另外如果不包含i,那么u,v都大于i,两者相加会相互抵消,不会影响x[i].至于u小于x[i]就更加显然了。

最后实现的时候注意一下边界条件。

13

这个题最简单的办法就是现在一个纬度上面计算出所有的子向量,然后将这些子向量作为基本元素在另一个纬度上面相加,最后就可以得到O(n^3)的算法。伪代码如下:

for each i from:    sum = [0.....0]#initialize all sum as zero    for each j from i to n:        #compute the sum[i,j] in the column k        for each k:            sum[k] += array[j][k]        #have computed all sum[k]        #use sum as element to compute max         max = max(max_sub(sum),max)

实现如下:

def max_rec(array):    n = len(array)    max_sum = 0    for i in range(n):        sum = [0]*n#initialize all sum as zero        for j in range(i,n):            #compute the sum[i,j] in the column k            for k in range(n):                sum[k] += array[j][k]            #have computed all sum[k]            #use sum as element to compute max             max_sum = max(max_subvec(sum),max_sum)    return max_sum

14,太简单了,O(N)算法可以搞定,依次扫描即可。

0 0
原创粉丝点击