算法竞赛入门经典第三章总结(python实现)

来源:互联网 发布:java 算法 快速排序 编辑:程序博客网 时间:2024/05/22 17:47
#开灯问题def N_lamps(n,k):    L = [0]*(n+1)    for i in range(1,k+1):        factor = 1        while(factor*i<=n):            L[factor*i] = 1-L[factor*i]#1代表开            factor += 1    for k,i in enumerate (L):        if(i==1):print(k,' ',end = '')         ###没啥好说的,简单的模拟  #蛇形矩阵def snake_matrix(n):    L = [[0]*n for i in range(n)]    dir = [(1,0),(0,-1),(-1,0),(0,1)]    i = 0;j = n-1;x = 1;    L[i][j] = 1;#先初始化第一个位置    while(x<n*n):        while(i<n-1 and (L[i+1][j]==0)):            L[i+1][j] = x+1;x+=1;i+=1        while(j>0 and (L[i][j-1]==0)):            L[i][j-1] = x+1;x+=1;j-=1        while(i>0 and (L[i-1][j]==0)):            L[i-1][j] = x+1;x+=1;i-=1        while(j<n-1 and  (L[i][j+1]==0)):            L[i][j+1] = x+1;x+=1;j+=1    for row in L:        print(row)###本题有两种思路,但是一个是跟着填入的数字走,根据当前坐标判断下一个数字应填在哪里,另一种思路就是跟着轨迹走,下,左,上,右不断循环.第一种方法相对麻烦(我就采取的第一种~~~~),因此给出了第二种的python实现. ###竖式问题,给定一个数字集合,找出所有形如abc*de的竖式算式,并且保证完整的竖式所有数字都是属于该集合。输出所有的竖式和解的行数。代码如下:number = 0def vertical_form_de(abc,data):    def test(buf,data):        for each in buf:            if(int(each) not in data):return False        return True    global number    for d in data:        for e in data:            de = d*10+e            x = abc*d;y = abc*e;z = abc*de            buf = str(x)+str(y)+str(z)            if(test(buf,data)):                number+=1;                print('%5d\nX%4d\n-------\n%5d\n%4d\n------\n%5d\n'%(abc,de,x,y,z))def  vertical_form_abc(data):    for a in data:        for b in data:            for c in data:                vertical_form_de(a*100+b*10+c,data)    print('The number of solutions = %d'%number)###书上给出的解法太暴力了,我的思路是从给定的集合里面来遍历.需要注意下输出格式,利用%5d,%4d来控制格式.def toTex(buf):    left_right = 0#0代表左,1代表右    new_buf = ''    for each in buf:        if(each == '"'):            if(left_right == 0):each = '“'            else: each = '"'            left_right = 1 - left_right        new_buf+=each    print(new_buf)#toTex('" To be or bot to be," quoth the Brad,"that is the question".')#字符错位问题####这题也很简单,关键是用好一个数组,一开始我想用map来解,但是这有些自找麻烦。。。。还是这个策略更容易实现.这也提醒我们使用map前要考虑有没有更简单的对应关系.def WERTYU(buf):    s = '`1234567890-=QWERTYUIOP[]\\ASDFGHJKL;ZXCVBNM,./'    for char in buf:        try:            pos = s.index(char)        except:            pos = -1        if(pos!=-1):print(s[pos-1],end = '')        else:print(char,end = '')#WERTYU('O S, GOMR YPFSU/')def palindromes(buf):    s = 'A   3  HIL JM O   2TUVWXY51SE Z  8 '    msg = ['is not a pal','is a regular pal','is a mirrored string','is a mirrored pal']    def rev(ch):        if(ch.isalpha()):return s[ord(ch)-ord('A')]        else :return s[ord(ch)-ord('0')+25]    print(buf,buf[::-1])    p = 1 if (buf[::-1]==buf) else 0#回文    old_buf = list(buf)    buf = list(map(rev,buf))    m = 1 if (buf[::-1]==old_buf) else 0    print(m,p,buf,old_buf)    print (msg[2*m+p])#palindromes('NOTAPALINDROME')#palindromes('2A3MEAS')#palindromes('ATOYOTA')###方法是采取一个数组来进行映射,注意几点:首先reverse会改变自己所绑定的值,因此较好的办法是采取[::-1]的切片,对于str和list都是通用的.另外四种情况的组合最后是采取一个类似二进制的表达来输出的.msg的作用很有意思.def master_mind(ans,guess):#test从guess本身考虑问题    def test(each):        tot = 0        wrong_occur = 0        mark = [0]*len(each)        for index in range(len(each)):            if(ans[index] == each[index]):tot+=1;mark[index]=1;        for index in range(0,len(each)):            if(mark[index]!=1):                pos = -1                while(True):                    try:                        pos = ans.index(each[index],pos+1)                        if(mark[pos]!=1):wrong_occur += 1;break;                    except:break        return tot,wrong_occur#test1从1-9数字的角度考虑问题    def test1(each):        A = 0;B = 0;        for index in range(len(each)):            if(ans[index] == each[index]):A+=1;        for d in range(1,10):            c1 = 0;c2 = 0;            for index in range(len(each)):                if(ans[index]==d):c1+=1;                if(each[index]==d):c2+=1;            B += min(c1,c2);        return (A,B-A)    for each in guess:        print(test(each))###其实这个问题书本上的解法很有意思,值得思考,我给出的解法需要多用一个数组作为标志数组,算法复杂度是O(n^2),首先求解出A并且做好标记,然后对guess序列的每一个数进行在ans中的查找,直到有一个位置的数字被找到且没有被标记过. ###而书本的答案则只需要O(n*m)的复杂度,其中m是代表可能出现的数字集合的长度. ###书本的答案采取的办法是统计每一个数字在ans和guess序列出现的次数,然后取两者中的最小值,这代表它们对B做出的贡献,然后不断累加即可.最后注意要减去A,因为不能计算已经正确包含的值.def mysum(x):    sum = x    while(x>0):        sum += x%10        x //= 10    return sumdef min_generator(n):    m = len(str(n))#获取n的位数    for x in range(n-9*m,n):#n-9m -> n-1        if(mysum(x)==n):print(x);return    print(0)#min_generator(121)#mysum(5555)def less(a,b):    a_l = len(a);b_l = len(b)    if(a_l > b_l): return less(b,a)    n = a_l if a_l < b_l else b_l    for i in range(n):        if(a[i]<b[i]):return True#小于        elif(a[i]>b[i]):return False#大于    if(b_l == a_l):return False#相等    else: return True#小于###这个题目不难,但是书上给出的答案有点意思,居然是空间换时间的做法,这个角度值得思考.但是还是有其他办法的,可以很容易的缩小枚举的范围是n-9m到n,m是n的位数.def circular_s(s):    temp = s    for i in range(len(s)):        if(less(temp,s)):ans = temp        temp = temp[1:]+temp[0]    print(ans)#circular_s('CGAGTCAGCT')def score(buf):#统计连续出现的O    curr_num = 0;tot = 0    for ch in buf:        if(ch=='O'):curr_num+=1;        else: curr_num = 0        tot += curr_num    print(tot)#score('OOXXOXXOOO')def Molar_Mass(buf):    weight = {'C':12.01,'H':1.008,'O':16.00,'N':14.01}    sum = 0.0;i = 0    length = len(buf)    while(i+1<length):        if (buf[i+1].isdigit()):sum += weight[buf[i]]*int(buf[i+1]);i+=2        else: sum += weight[buf[i]];i+=1;    if(i==length-1):sum+= weight[buf[i]]    print(sum)#Molar_Mass('C6H5OH2')###唯一需要注意的是最后一个分子def get_zero(i,num):    tot = 0    u = 1;    for j in range(1,i+1):        x = j*u;        tot += x        u *= 10;    tot*=9    return  tot - num*9def digit_count(n):    k = 0;i = 0;    while(True):        if((k*10+9) <= n):k = k*10+9;i+=1;        else:break    gap = n - k    sum = [i*(k+1)//10]*10;    sum[0] = get_zero(i,sum[1])    for digit in range(k+1,n+1):        for ch in str(digit):            sum[ord(ch)-ord('0')]+=1    print(sum)#digit_count(5000)####这个题目暴力解就太简单了,这里稍微用了一点数学的知识: ####我们首先看一看1-999的出现情况,首先假设数字出现的规律是001-999,这样因为每一位都是平均分配的,所以每一位出现的次数是3*1000/10 = 300def perodic(buf):    def test(s):        k = len(s)        for i in range(len(buf)//k):            if(s!=buf[i*k:(i+1)*k]): return False        return True    beg = '';end = ''    length = len(buf)    for i in range(length//2 + 1):        beg += buf[i]        end = buf[length-i-1]+end        if(beg == end and test(beg)):print(len(beg));return    print(len(buf))#perodic('abccbaabccxba') ###这里的算法复杂度是n^2,先从两头开始比较,最坏情况下比较的次数是1+2+3+....(n/2) = n^2/8,然后进行检验,检验的比较次数是n. ###如果采取最直接的暴力比较法,最坏情况下的比较次数是(n/2)*n = n^2/2,显然上面的算法要好一些.但是还是不能降低复杂度的量级.... #空格迷题def get_pos(matrix):        for i,k in enumerate(matrix):            for j,item in enumerate(k):                if(item == ' '):return[i,j]def Puzzle(matrix,command):    empty_pos = get_pos(matrix)    dir = {'A':[-1,0],'B':[1,0],'L':[0,-1],'R':[0,1]}    def move(instruction):        nonlocal empty_pos#声明它不是move的局部变量        old_i = empty_pos[0]        old_j = empty_pos[1]        if(instruction not in dir):return False        i = old_i + dir[instruction][0]        j = old_j + dir[instruction][1]        if(i<5 and i >0 and j<5 and j>0 ):            matrix[old_i][old_j],matrix[i][j] = matrix[i][j],matrix[old_i][old_j]#交换两个元素            empty_pos = [i,j]            return True        else:return False    for ins in command:        if(not move(ins)):print('This puzzle has no final configuration');return    for i in matrix:        print(i)A = [['T','R','G','S','J'],['X','D','O','K','I'],['M',' ','V','L','N'],['W','P','A','B','E'],['U','Q','H','C','F']]Puzzle(A,'ARR')

简单的模拟而已,需要注意的是python3 nonlocal的用法可以用来修改外部的自由变量.

0 0
原创粉丝点击