您的位置:首页 > 编程语言 > Python开发

有关编程之美的试题python实现

2016-08-05 11:00 495 查看
class BSTreeNode:

    def __init__(self,value=None,left=None,right=None):

        self.value=value

        self.left=left

        self.right=right

def ConnectTreeNodes(pNodeA1, pNodeA2, pNodeA3):

    pNodeA1.left=pNodeA2

    pNodeA1.right=pNodeA3

########################################################################

##                    编程之美1.1让cpu曲线听你指挥                       ##

########################################################################

## 解法一:让cpu跑idle和busy两个不同的循环,控制时间比例,busy可用空循环,idle可

##        用sleep()

import time

def algorithm1():

    while True:

        #调整适当的n,运行时间也是0.01秒,这个n不对

        for i in range(9600000):

            pass

        time.sleep(0.01)

def algorithm2():

    busytime=0.02

    idletime=0.01

    while True:

        startTime=time.time()

        while time.time()-startTime<busytime:

            print(time.time()-startTime)

        time.sleep(idletime)

import math

def algorithm3():

    count=200#抽样频率

    busy=[0]*count

    idle=[0]*count

    for i in range(count):

        busy[i]=(1+math.sin(math.pi*i*2/count))/count#0~2之间-》0~0.01之间

        idle[i]=0.01-busy[i]

    j=0

    while True:

        startTime=time.time()

        j=j%200

        while time.time()-startTime<busy[j]:

            print(time.time()-startTime)

        time.sleep(idle[j])

        j=j+1

def test1_1():

    #algorithm1()

    #algorithm2()

    algorithm3()

########################################################################

##            编程之美1.2输出将帅的所有位置(只能用一个变量)                 ##

###################################
4000
#####################################

def getPosition():

    #假设A,B的位置为0~9,把B放在10位上

    #1 2 3

    #4 5 6

    #7 8 9

    for i in range(11,100):

        if (i%10==0) or i%10%3==(i//10)%3:

            continue

        print('B:{},A:{}'.format(i%10,i//10))

def test1_2():

    getPosition()

########################################################################

##                    编程之美1.3 翻转烙饼,使其有序                      ##

########################################################################

# 注意这里不是一般的排序问题,max的位置你是知道的,只能用'翻转'操作

# 考虑这样一种算法,把最大的那个烙饼翻到最下面需要2次操作,完成之后,对上面的n-1的烙饼

#                重复这一算法,这样最多只要2(n-1)次操作就可以完成

class CPrefixSorting:

    def __init__(self,pCakeArray,nCakeCnt):

        self.m_nCakeCnt=nCakeCnt#烙饼个数

        self.m_nMaxSwap=self.UpBound(nCakeCnt);#最多交换次数。根据前面的推断,这里最多为m_nCakeCnt * 2

        self.m_CakeArray=list(pCakeArray)#烙饼信息数组

        self.m_SwapArray=[0]*self.m_nMaxSwap#交换结果数组

        self.m_ReverseCakeArray=list(pCakeArray)#当前翻转烙饼信息数组

        self.m_ReverseCakeArraySwap=[0]*self.m_nMaxSwap#当前翻转烙饼交换结果数组

        self.m_nSearch=0#当前搜索次数信息

     # 计算烙饼翻转信息

     # @param

     # pCakeArray    存储烙饼索引数组

     # nCakeCnt    烙饼个数

     #

    def Run(self):

        self.Search(0)

     # 输出烙饼具体翻转的次数

    def Output(self):

        print(self.m_ReverseCakeArray)

        print(self.m_ReverseCakeArraySwap[0:self.m_nMaxSwap])

        print("\n |Search Times| : %d\n"%self.m_nSearch);

        print("Total Swap times = %d\n"%self.m_nMaxSwap);

    # 寻找当前翻转的上界

    def UpBound(self,nCakeCnt):

         return nCakeCnt*2

    # 寻找当前翻转的下界

    def LowerBound(self,pCakeArray,nCakeCnt):

        ret = 0

        # 根据当前数组的排序信息情况来判断最少需要交换多少次

        for i in range(1,nCakeCnt):

               # 判断位置相邻的两个烙饼,是否为尺寸排序上相邻的

            t = pCakeArray[i] - pCakeArray[i-1];

            if (t == 1) or (t == -1):

                pass

            else:

                ret+=1

        return ret

     # 排序的主函数

    def Search(self,step):

        #print('step:%d'%step)

        self.m_nSearch+=1

        # 估算这次搜索所需要的最小交换次数

        nEstimate = self.LowerBound(self.m_ReverseCakeArray,self.m_nCakeCnt)

        #print('lower bound:%d'%nEstimate)

        if (step + nEstimate >= self.m_nMaxSwap):

            return

        # 如果已经排好序,即翻转完成,输出结果

        if self.IsSorted(self.m_ReverseCakeArray,self.m_nCakeCnt):

            print('find min step:%d'%step)

            self.m_nMaxSwap = step;

            self.Output()

            return

        # 递归进行翻转

        # 这里是一个遍历的枚举算法,枚举出每个可能的交换方式,然后剪枝

        for i in range(1,self.m_nCakeCnt):

            #print('change:%d'%i)

            #依次交换

            self.Revert(0, i)

            self.m_ReverseCakeArraySwap[step] = i

            #递归的操作子序列

            self.Search(step + 1)

            #注意完成之后要还原,继续搜索

            self.Revert(0, i)

     # true : 已经排好序

     # false : 未排序

    def IsSorted(self,pCakeArray,nCakeCnt):

        for i in range(1,nCakeCnt):

            if(pCakeArray[i-1] > pCakeArray[i]):

               return False

        return True

    # 翻转烙饼信息

    def Revert(self, nBegin,nEnd):

        if nBegin>=nEnd:

            return

        self.m_ReverseCakeArray[nBegin:nEnd+1]=reversed(self.m_ReverseCakeArray[nBegin:nEnd+1])

        #print(self.m_ReverseCakeArray)

def test1_3():

    a=CPrefixSorting([3,2,1,6,5,4,9,8,7,0],10)

    a.Run()

########################################################################

##                    编程之美1.4 买书问题                               ##

########################################################################

# 共5种,每本8块,买2本不同的书折扣5%,3本10%,4本20%,5本25%,

# 同一种折扣规则只能使用一次:也即:

# 如果买了2本1,一本2,那么最多只能对其中一本1和一本2使用5%折扣,另一本1就不能折扣了

# 这里贪心策略行不通

# 算法一 动态规划,缩小为较小的子问题

Recount=[1,0.95,0.9,0.8,0.75]#折扣

def buyBook(inputList):

    #如果有一个<0

    sortedInputList=sorted(inputList,reverse=True)

    if sortedInputList[0]<0:

        return 99999

    #如果有0或者1

    #买得最多的那本数量

    maxBookCount=sortedInputList[0]

    if maxBookCount==0:

        return 0

    if maxBookCount==1:

        #print('buy:',end='')

        #print(sortedInputList)

        count=sortedInputList.count(1)

        return count*8*Recount[count-1]

    a,b,c,d,e=sortedInputList

    return min([buyBook([1,0,0,0,0])+buyBook([a-1,b,c,d,e]),

                buyBook([1,1,0,0,0])+buyBook([a-1,b-1,c,d,e]),

                buyBook([1,1,1,0,0])+buyBook([a-1,b-1,c-1,d,e]),

                buyBook([1,1,1,1,0])+buyBook([a-1,b-1,c-1,d-1,e]),

                buyBook([1,1,1,1,1])+buyBook([a-1,b-1,c-1,d-1,e-1])])

def test1_4():

    print(buyBook([2,2,2,1,1]))

########################################################################

##                    编程之美1.5 快速找出故障机器                        ##

########################################################################

# 如果仅有一台机器出了故障,可以使用找异或值的方法,只需要存一个变量

def findOneBroken(alist):

    result=0

    for i in range(len(alist)):

        result=alist[i]^result

    return result

# 如果两台机器出了故障且是不同的

def findTwoBrokenDiff(alist):

    tempresut=findOneBroken(alist)

    numer=findnumber(tempresut)

    result1=0

    result2=0

    #分成两类,这个位数上是一的和不是一的

    for i in range(len(alist)):

        if alist[i]&numer==0:

            result1=alist[i]^result1

        else:

            result2=alist[i]^result2

    return result1,result2

# 一个二进制数最低的一个为1的位数,并且提取出来

def findnumber(i):

    k=0

    endNumer=i&1

    while endNumer!=1:

        k+=1

        endNumer=(i>>1&1)

    return 1<<k

from functools import reduce

#使用'不变量的方法求解',总的id和减去剩下的就是坏掉的id和x+y=a

#如果两个id不同还需要一个方程可以用x*y=b

def findbrokenWithEquation(origin,now):

    originSum=sum(origin)

    nowSum=sum(now)

    originMul=reduce(lambda x,y:x*y,origin)

    nowMul=reduce(lambda x,y:x*y,now)

    a=originSum-nowSum

    b=originMul/nowMul

    return (a+math.sqrt(a**2-4*b))/2,abs(a-math.sqrt(a**2-4*b))/2

def test1_5():

    print(findOneBroken([1,1,2,2,3,4,4,5,5,6,6]))

    print(findTwoBrokenDiff([1,1,2,2,3,4,5,5,6,6]))

    print(findbrokenWithEquation([1,1,2,2,3,3,4,4,5,5,6,6],[1,1,2,2,3,4,5,5,6,6]))

    print(findbrokenWithEquation([1,1,2,2,3,3,4,4,5,5,6,6],[1,1,2,2,4,4,5,5,6,6]))

    print(findnumber(6))

########################################################################

##                    编程之美1.6 饮料供货                             ##

########################################################################

# 饮料的总容量有上限V,求一种组合使得总满意度最大

# 结果第k种饮料的数量*满意度+减去第k种饮料的最优结果

#  使用动态规划,并且可以纪录子问题的解

# 子问题的记录项表,假设从i到T种饮料中,

                                # 找出容量总和为V'的一个方案,满意度最多能够达到

                               # opt(V',i,T-1),存储于opt[V'][i],

                               # 初始化时opt中存储值为-1,表示该子问题尚未求解

opt=[]

def Cal(V,type,C,H,T):

    global ret

    print(ret)

    #最多T种饮料

    if type == T:

        if V==0:

            return 0

        else:

            return -9999

    if V < 0:

        return -9999

    elif(V == 0):

          return 0

    elif(opt[V][type] != -1):

          return opt[V][type]        # 该子问题已求解,则直接返回子问题的解;

                                     # 子问题尚未求解,则求解该子问题

    temp=0

    for i in range(C[type]):

        #去掉一种饮料算子问题的最优解

        #去掉的方法有0~C[type](这种饮料的最大值)种,取这几种结果中最大的

        temp = Cal(V-i*C[type],type-1)

        print(temp)

        if(temp != -9999):

            temp += H[type] * i

            if(temp > ret):

                ret = temp

    opt[V][type]=ret

    return ret

def memoize(f):

    memo = {}

    def helper(a,b,c,d,e):

        if (a,b) not in memo:

            memo[(a,b)] = f(a,b,c,d,e)

        return memo[(a,b)]

    return helper

def test1_6():

    V=10#总容量

    T=10#T种饮料

    type=T

    ret=0

    opt=[[-1]*(V+1)]*(T+1)

    C=[100]*T

    H=[100]*T

    m_Cal=memoize(Cal)

    print(m_Cal(1000,T,C,H,T))

########################################################################

##                    编程之美1.7 光影切割问题                          ##

########################################################################

# 此算法的核心是先寻找分块数和交点数的关系式,然后可以发现交点数就是和边界交点次序的

# 逆序数,从而问题转发为逆序数问题

#寻找逆序数

#逆序数是归并排序的副产品

num = 0

def merge_sort(data):

    if (len(data)<=1):

        return data

    index  =  len(data)//2

    lst1 = data[:index]

    lst2 = data[index:]

    left = merge_sort(lst1)

    right = merge_sort(lst2)

    return merge(left, right)

#这里merge算法不是很高效,待改

def merge(lst1, lst2):

    """to Merge two list together"""

    list = []

    while(len(lst1)>0 and len(lst2)>0):

        data1 = lst1[0]

        data2 = lst2[0]

        if (data1<=data2):

            list.append(lst1.pop(0))

        else:

            global num

            num = num + len(lst1)

            list.append(lst2.pop(0))

    if(len(lst1)>0):

        list.extend(lst1)

    else:

        list.extend(lst2)

    return list

def test1_7():

    merge_sort([4,3,2,1])

    print(num)

########################################################################

##                    编程之美1.8 电梯算法                             ##

########################################################################

# 电梯只停一层楼,停在哪里乘客要爬楼梯最少

# 此题的关键在于寻找delta函数,如果停在i层楼,要爬总数是Y层,有N1,N2,N3分别指实际目标

# 在i层之下,i层,i层之上,那么停在i+1层要爬Y+N1+N2-N3,i-1层:Y-N1+N2+N3,可以看出

# 当N1+N2-N3<0的时候应改i+1,N2+N3-N1<0->i-1;=0,i不变,因此只要找到这样的i,使得

# N1+N2-N3>=0;N2+N3-N1>=0

def findFloor(alist):

    for i in range(len(alist)):

        N1=sum(alist[:i])

        N2=alist[i]

        N3=sum(alist[i+1:])

        if N1+N2-N3>=0 and N2+N3-N1>=0:

            return i

def test1_8():

    print(findFloor([4,0,3,2,1,0,4,0,8]))

########################################################################

##                 编程之美1.9 高效率地安排见面会                        ##

########################################################################

# 如四个见面会起止时间分别为A[1,5],B[2,3],C[3,4],D[3,6]求最少需要安排多少面试地点

# (多少人来面试?)

# 最优的算法是把开始时间结束时间都排序,遍历时遇到一个B(开始时间)m+1;遇到一个E:m-1

# 这样m遍历过程中的最大值就是解

def findMinPlace(list):

    total=[]

    for item in list:

        total.append((item[0],'B'))

        total.append((item[1],'E'))

    total=sorted(total,key=lambda x:x[0])

    print(total)

    m=0

    maxm=0

    for i in range(len(total)):

        if total[i][1]=='B':

            m+=1

            if
167b7
m>maxm:

                maxm=m

        else:

            m-=1

    return maxm

#如果是一对于的问题,即n个学生对m个项目中的一个或者几个感兴趣,怎样安排可以使得项目介绍 的总时间最短

# 这个是典型的图的着色问题,对于图使用最少的颜色使得对于任何一个边,边的两个顶点颜色都不一样

# 两个典型的解法:1.回溯法 2.贪心法

# 1.回溯法,输入n个点,m个颜色,m从低到高看有没有解,可以找到最小的解m

def ColorOk(k,G,color): #判断顶 点k的着⾊色是否发⽣生冲突

    for i in range(k):

        if G[k][i]==1 and color[i]==color[k]:

            return False

    return True

def GraphColor(n,m,G):

    color=[0]*n

    k=0

    while k>=0:

        color[k]=color[k]+1

        while color[k]<=m:

            if ColorOk(k,G,color):

                break

            else:

                color[k]=color[k]+1#搜索下一个颜⾊

        if color[k]<=m and k==n-1: #求解完毕,输出解

            print(color)

            return

        elif(color[k]<=m and k<n-1):

            k=k+1 #处理下⼀一个顶点

        else:

            color[k]=0;

            k=k-1; #回溯

def ColorOk2(i,k,n,G,color): #判断顶 点k的着⾊色是否发⽣生冲突

    for j in range(n):

        if G[i][j]==1 and color[j]==k:

            return False

    return True

#贪心法

def GraphColor2(n,G):

    color=[0]*n

    color[0]=1

    k=1

    while color.count(0)!=0:

        for i in range(n):

            if color[i]==0 and ColorOk2(i,k,n,G,color):

                color[i]=k

        k+=1

    print(k,color)

def test1_9():

    print(findMinPlace([[1,5],[2,3],[3,4],[3,6]]))

    G=[[1,1,1,0,0],

       [1,1,1,1,1],

       [1,1,1,0,1],

       [0,1,0,1,1],

       [0,1,1,1,1]]

    GraphColor(5,3,G)#m最小是3的时候有解,说明m最小可以是3

    GraphColor2(5,G)#找到的不是最优解

########################################################################

##                        编程之美1.11-1.13 取石头                         ##

########################################################################

#1.11

#每次取一个或者两个相邻的,求必胜策略

#取中间的一个(奇数),或中间两个(偶数),这样对手取任何石头,取他对称的石头即可

#1.12 A分堆,B先取

#关键是找出安全局面:(1,1)是安全局面,先取的输

#                =>(1,x) x>1不是安全局面,因为对手可以一步转化为自己的安全局面

#                =>(m,m) m>1 是安全局面 因为对手怎么取,都不能一步变成安全局面,循环不变式

# 所以N为偶数的时候,分成两堆相同的,可以保证自己赢

# N是奇数的时候,(1,1,1)是非安全局面

#              (1,1,x)是非安全局面

#              (1,2,x)是安全局面

#              (1,x,x)是非安全局面对手取1,(x,x)安全

#              (1,x,y)x!=y 是非安全局面,因为对手可以转换为(1,2,x)

#

#1.13 有两堆石头,可以从两堆取等数量,或者其中一堆取任意

########################################################################

##                        编程之美1.14 连连看                         ##

########################################################################

# 算法的核心是广度优先搜索,对于A一步可以到达的领域集合中如果有有A',那么A,A'距离为0转折

#  对于A一步可以到达的空格子的领域集合中如果有A',那么距离为1转折``````````

########################################################################

##                        编程之美1.15 数独                          ##

########################################################################

# 见C++程序

########################################################################

##                        编程之美1.16 24点                          ##

########################################################################

#递归算法

# 见C++程序

########################################################################

##                   编程之美2.1 求二进制数字中1的个数                    ##

########################################################################

#1.求余数的方法

def findOnes(number):

    sum_one=0

    while number:

        sum_one+=number%2

        number=number//2

    return sum_one

#2.位操作方法,思路同上,只是表述不一样

def findOnes2(number):

    sum_one=0

    while number:

        sum_one+=number&0x1

        number=number>>1

    return sum_one

#3.位操作,基于这样的常用方法:使得一个二进制数a最低的1变成0方法是;a=a&(a-1)

def findOnes3(number):

    sum_one=0

    while number:

        number=number&(number-1)

        print(number)

        sum_one+=1

    return sum_one

#4. 查表法,既然是8位二进制数,直接把256个结果存在一个字典里就可以了

# 算法略

#5 算法5 用1,不断移动来看每一位上是不是1

def findOnes5(number):

    k=1

    sum_one=0

    for i in range(1,32):

        if number&k:

            sum_one+=1

        k=k<<1

    return sum_one

def test2_1():

    print(findOnes3(7))

    print(findOnes5(7))

########################################################################

##                       编程之美2.2 不要被阶乘吓倒                      ##

########################################################################

#1.求N!二进制表示中末尾0的个数

# 分析后发现,只要求5的指数次数即可

def endZeros(numberN):

    ret=0

    while numberN:

        ret+=numberN//5

        numberN=numberN//5

    return ret

#由于python不会溢出,可以用这个算法验证结果

def endZeros2(numberN):

    ret=0

    resultN=reduce(lambda x,y:x*y,range(1,numberN+1))

    print(resultN)

    while resultN%10==0:

        ret+=1

        resultN=resultN//10

    return ret

#2.求N!二进制表示中最低位1的位置

# 首先看一个二进制数,最低的1的位置就是可以被2整除的次数+1,(不能整除说明最后一位是1了)

# 这样就转化成求N!中质因数2的个数,即N/2+N/4+```

def findLowestOne(numberN):

    ret=0

    while numberN:

        numberN=numberN>>1

        ret+=numberN

    return ret

#由于python不会溢出,可以用这个算法验证结果

def findLowestOne2(numberN):

    ret=0

    resultN=reduce(lambda x,y:x*y,range(1,numberN+1))

    while resultN%2==0:

        ret+=1

        resultN=resultN>>1

    return ret

def test2_2():

    print(endZeros(100))

    print(endZeros2(100))

    print(findLowestOne(100))

    print(findLowestOne2(100))

########################################################################

##                       编程之美2.3 寻找水王                           ##

########################################################################

# 水王发帖的数量大于N/2找到他

# 思路核心是大于N/2,那么删除掉两个不一样的,剩下的还是大于N/2,

# 如果给他计数那么,不一样的-1,一样的+1,那么水王的id一定能>1

def findMostCommon(list):

    tempResult=0

    countOfTempResult=0

    for item in list:

        if countOfTempResult==0:

            tempResult=item

        if item==tempResult:

            countOfTempResult+=1

        else:

            countOfTempResult-=1

    return tempResult

#算法二 用一个hash表保存频数

#算法三 既然>N/2,那么如果找出数组第N/2 大的数,那么这个数就是频数大于N/2的数

#所以算法就转换成了O(N)算法的寻找第k大数

import  random

def Partition(alist,start,end):

    index=random.randint(start,end)

    alist[index],alist[end]=alist[end],alist[index]

    small=start-1

    index=start

    while index<end:

        if alist[index]<alist[end]:

            small+=1

            if small!=index:

                alist[small],alist[index]=alist[index],alist[small]

        index+=1

    small+=1

    alist[small],alist[end]=alist[end],alist[small]

    return small

def findKLargest(alist,begin,end,k):

    mid=Partition(alist,begin,end)

    if mid==k:

        return alist[k]

    elif mid>k:

        return findKLargest(alist,begin,mid-1,k)

    else:

        return findKLargest(alist,mid+1,end,k-mid)

def test2_3():

    print(findMostCommon([1, 2, 3, 4, 2, 5, 2, 2, 3, 2, 5, 2]))

    print(findKLargest([1, 2, 3, 4, 2, 5, 2, 2, 3, 2, 5, 2],0,11,6))

########################################################################

##                       编程之美2.4  1的数目                           ##

########################################################################

# 找出1.....N中N个数字中1的数目:如1,2,3,4,5,6,7,8,9,10,11,12 中有5个1

# 算法1,直接遍历求解,复杂度为O(N*logN)

def findOnesToN(numberN):

    def findOnesOfN(numberN):

        ret=0

        while numberN:

            ret+=(numberN%10==1)

            numberN=numberN//10

        # print(ret)

        return ret

    ret=0

    for i in range(1,numberN+1):

        ret+=findOnesOfN(i)

    return ret

# 算法2,1的个数为个位1+十位1+...

def findOnesToN2(n):

    iCount = 0

    iFactor = 1

    iLowerNum = 0

    iCurrNum = 0

    iHigherNum = 0

    while n // iFactor:

        #低位,当前位,高位

        iLowerNum = n - (n //iFactor) * iFactor

        iCurrNum = (n // iFactor) % 10

        iHigherNum = n // (iFactor * 10)

        if iCurrNum==0:

            iCount += iHigherNum * iFactor

        elif iCurrNum== 1:

            iCount += iHigherNum * iFactor + iLowerNum + 1

        else:

            iCount += (iHigherNum + 1) * iFactor

        iFactor *= 10

    return iCount

def test2_4():

    print(findOnesToN(12))

    print(findOnesToN2(99))

########################################################################

##                    编程之美2.5 数组中k个最大的数                      ##

########################################################################

#算法一 排序

def findKMax(list,k):

    return sorted(list)[-k:]

import random

#算法二 递归算法

#递归的分成两组,Sa,Sb其中Sa中的元素都小于Sb

def patition(list):

    a=list[len(list)//2]

    Sa=[]

    Sb=[]

    for item in list:

        if item>=a:

            Sa.append(item)

        else:

            Sb.append(item)

    return (Sa,Sb)

def findKMax2(list,k):

    if k<=0:

        return []

    if len(list)<=k:

        return list

    Sa,Sb=patition(list)

    a=findKMax2(Sa,k)

    b=findKMax2(Sb,k-len(Sa))

    # print(a,b)

    return a+b

#算法三 使用一个长度为k的最小堆作为数据结构保存最大的k个数

# 保持堆性质,对于位置i

def min_heapify(list,i):

    K=len(list)

    p=i#父亲节点

    while i < K:

        # 左儿子

        q = 2 * p + 1

        if q >= K:

            break

        # 如果有右儿子而且有儿子更小

        if q < K-1  and  list[q + 1] < list[q]:

            q = q + 1;

        if list[q]< list[p]:#违反堆性质

            list[p],list[q] = list[q],list[p]#交换

            p = q

        else:

            break

def build_Heap(list):

    i=len(list)//2

    while i>=0:

        min_heapify(list,i)

        i-=1

    return list

def findKMax3(list,k):

    heap=list[:k]

    heap=build_Heap(heap)

    for item in list[k:]:

        if item<=heap[0]:

            break

        else:

            heap[0]=item

            min_heapify(heap,0)

    return heap

#算法四 桶排序,计数排序的思想

def findKMax4(list,k):

    numCount=[0]*len(list)

    for item in list:

        numCount[item]+=1

    result=[]

    sumCount=0

    i=len(numCount)-1

    while sumCount<=k:

        sumCount+=numCount[i]

        result.extend([i]*numCount[i])

        i-=1

    return result

def test2_5():

    alist=list(range(20000))

    # print(findKMax(alist,10))

    # print(findKMax2(alist,10))

    # print(build_Heap([23,2,12,2,43,5,3,6,7]))

    print(findKMax3(alist,20))

    print(findKMax4(alist,20))

########################################################################

##                    编程之美2.6 精确表示浮点数                        ##

########################################################################

# 得出推导公式 10^m*Y-Y=b1b2..bm

########################################################################

##                    编程之美2.7 最大公约数问题                        ##

########################################################################

# 基本解法:辗转相除法

def gcd(a,b):

    if b==0:

        return a

    else:

        return gcd(b,a%b)

# 解法2:大整数取模消耗较大,考虑到x>y,的时候 f(x,y)=f(x-y,y)这样可以化成小整数求解

# 但是缺点是迭代次数变多了

def bigIntGcd(a,b):

    if a<b:

        return bigIntGcd(b,a)

    if b==0:

        return a

    else:

        return bigIntGcd(a-b,b)

# 算法3:对偶数除以2,减小运算次数

def isEven(n):

    return n&1==0

def bigIntGcd2(a,b):

    if a<b:

        return bigIntGcd(b,a)

    if b==0:

        return a

    else:

        if isEven(a):

            if isEven(b):

                return bigIntGcd2(a>>1,b>>1)<<1

            else:

                return bigIntGcd2(a>>1,b)

        else:

            if isEven(b):

                return bigIntGcd2(a,b>>1)

            else:

                return bigIntGcd2(a-b,b)

def test2_7():

    print(gcd(36,27))

    # print(bigIntGcd(131111811222,2131112))

    print(bigIntGcd2(131111811222,2131112))

########################################################################

##                    编程之美2.8 找符合条件的整数                       ##

########################################################################

# 给定一个正整数N,求最小正整数M使得N*M十进制表示中只有0或1

# 遍历X

import itertools

def findM(n):

# 算法会重复遍历,待改进

    i=0x1

    while i<99999999999:

        b=int('{0:b}'.format(i))

        if b%n==0:

            return b,b//n

        i+=1

def test2_8():

    print(findM(99))

########################################################################

##               编程之美2.10 寻找数组中的最大最小值                     ##

########################################################################

# 1.如果看成独立的两个问题,至少需要2N次比较

# 2.对数组中的元素两两比较,每两个数中,大的都放在奇数位小的放在偶数位,这样需要N/2+N次比较

#   这种算法不一定要改变原数组,遍历的时候得到两位中的大的和小的,把小的和min,大的和max比较即可

# 3.分治算法,也需要3N/2次比较

########################################################################

##                  编程之美2.11 寻找最近的点对                         ##

########################################################################

# 典型的分治算法的题目

# 如果事数组,可以用桶排序,只要O(N)时间(放入桶中-N,扫瞄一遍桶-N)

########################################################################

##                  编程之美2.12 快速寻找满足条件的两个数                 ##

########################################################################

# 找出一个数组中的两个数字a,b,使得其和为c

# 先排序的两个算法:注意这里只是找一个解,如果要找出所有解,可以用算法2或者算法3变化一下

# 算法1

def findSumC(list,c):

    list=sorted(list)

    sumab=0

    for i in range(len(list)-1):

        a,b=list[i],list[i+1]

        sumab=a+b

        if sumab==c:

            return a,b

        elif sumab>c:

            break

# 算法2 首尾变化,这里已经改成了找所有解

def findSumC2(list,c):

    list=sorted(list)

    a=0

    b=len(list)-1

    resut=[]

    while a<b:

        sumab=list[a]+list[b]

        if sumab==c:

            resut.append((list[a],list[b]))

            a+=1

        elif sumab<c:

            a+=1

        else:

            b-=1

    return resut

# 算法3 使用哈希表

def findSumC3(list,c):

    adict={}

    result=[]

    for item in list:

        adict[item]=1

    # print(adict)

    for item in list:

        #?

        if c-item<item:

            break

        if c-item in adict:

            result.append((item,c-item))

    return result

def test2_12():

    print(findSumC(list(range(100)),25))

    print(findSumC2(list(range(100)),25))

    print(findSumC3(list(range(100)),25))

########################################################################

##                  编程之美2.13 求字数组的最大乘积                    ##

########################################################################

# N维数组,找一个字数组N-1维,使得数组乘积最大,只能用乘法

# 算法一,从低到高,排除那个i,计算剩下的乘积

def findMaxN_1(list):

    result=0

    for i in range(len(list)):

        temp=reduce(lambda x,y:x*y,list[:i]+list[i+1:])

        if temp>result:

            result=temp

    return result

# 算法2 计算整个乘积P,P=0;>0;<0三种情况

def findMaxN_2(list):

    temp=reduce(lambda x,y:x*y,list)

    if temp==0:

        i=list.index(0)

        temp=reduce(lambda x,y:x*y,list[:i]+list[i+1:])

        if temp<0:

            temp=0

    elif temp>0:

        i=list.index(min([item for item in list if item>0]))

        temp=reduce(lambda x,y:x*y,list[:i]+list[i+1:])

    else:

        i=i=list.index(max([item for item in list if item<0]))

        temp=reduce(lambda x,y:x*y,list[:i]+list[i+1:])

    return  temp

def test2_13():

    print(findMaxN_1([12,3,2,4,345,32,12]))

    print(findMaxN_2([12,-3,0,4,345,32,12]))

########################################################################

##                  编程之美2.14 求子数组之和的最大值                    ##

########################################################################

# 这个题都烂了,不写了,不会的面壁

########################################################################

##                  编程之美2.15 求子数组之和的最大值(二维)                ##

########################################################################

# 思路是存储部分和,把解转化为部分和(根据右上角的位置,算其和整个图的左下角组成的图形面积)的函数

########################################################################

##                  编程之美2.16 数组中的最长递增子序列                  ##

########################################################################

'待补+逆序数'

########################################################################

##                      编程之美2.17 数组循环移位                       ##

########################################################################

# [a,b,c,d,e]=>[e,a,b,c,d]

# [abcd1234]算法的核心是:交换abcd,1234的位置,如何交换呢,可以用三次逆序实现:

#  1.abcd 逆 [dcba1234]

#  2.1234 逆 [dcba4321]

#  3.整个  逆 [1234abcd]  完成

#注意这个是演示算法,实际reverse可以只用一个变量\

def leftMoveN(alist,N):

    N=N%len(alist)

    alist[:N]=list(reversed(alist[:N]))

    alist[N:]=list(reversed(alist[N:]))

    # print(alist)

    return list(reversed(alist))

def test2_17():

    print(leftMoveN([12,3,2,4,345,32,12],1))

########################################################################

##                      编程之美2.18 数组分割                           ##

########################################################################

#2n个元素的数组,找到两个子数组,n维使得其和尽量相等

#如果数组的总和是sum,那么找到一个最接近sum/2即可,不妨设<=sum/2

#使用动态规划的思想,若F[i][j][k]表示从i个元素中取j个使得其尽量接近k,那么

# F[i][j][k]=max(F[i-1][j][k],F[i-1][j-1][k-A[j]]+A[j])

#                 取了第i个元素,没取第i个元素

'这道题是背包问题,待补充背包问题的算法介绍'

def findTwoN(list,n):

    sumList=sum(list)

    print(sumList)

    F=[[[0]*(sumList//2+1)]*(n+1)]*(2*n+1)

    Path=F.copy()

    # print(F)

    nLimit=n

    for i in range(1,2*n+1):

        nLimit==min(i,n)

        for j in range(1,nLimit+1):

            for k in range(1,sumList//2+1):

                # print(i,j,k)

                F[i][j][k]=F[i-1][j][k]

                if(k>=list[i-1] and F[i][j][k]<F[i-1][j-1][k-list[i-1]]+list[i-1]):

                    F[i][j][k]=F[i-1][j-1][k-list[i-1]]+list[i-1]

                    Path[i][j][k]=1

    return F[2*n]
[sumList//2]

#可以F[i]始终与F[i-1]有关,可降维

def findTwoN2(list,n):

    sumList=sum(list)

    print(sumList)

    F=[[0]*(sumList//2+1)]*(n+1)

    # print(F)

    nLimit=n

    for i in range(1,2*n+1):

        nLimit==min(i,n)

        for j in range(1,nLimit+1):

            for k in range(1,sumList//2+1):

                # print(i,j,k)

                if(k>=list[i-1] and F[j][k]<F[j-1][k-list[i-1]]+list[i-1]):

                    F[j][k]=F[j-1][k-list[i-1]]+list[i-1]

    return F
[sumList//2]

def test2_18():

    print(findTwoN([12,3,2,4,34,32,12,5],4))

    print(findTwoN2([12,3,2,4,34,32,12,5],4))

########################################################################

##                      编程之美3.1 字符串移位的包含问题                  ##

########################################################################

# 字符串'ABCD'循环移动之后包含'DAB'

# 此题的核心是'ABCD'=>'ABCDABCD'其中的3字符字串就是可以得到的所有3字符字串

#类似题目,移动字符串ABCD12向右移动两位,12ABCD,但是最多使用两个变量空间

# 一个做法同上拼接后切割,但是这样需要多余的空间,不符合要求,这种做法实际就是字符串复制

# 算法1:  算法 2.17 用三次旋转实现,线性时间,但是只使用一个旋转用的变量

#算法2:双指针移动法:对于一个字符串或者数组123456789,要向左移动m位,那么可以用两个指针

# p1=0;p2=p1+m;p1,p2一边向前移动一边交换p1,p2,对于末尾的递归实现上述步骤可以实现移动

# 如1234,m=2,=>3214=>3412 完成。12345,m=2 32145=》34125=》34521=》34512

#stl里的rotate算法,用到了gcd的原理

def leftRotate(astr,n,m,head,tail):

    #n 待处理部分的字符串长度,m:待处理部分的旋转长度

    #head:待处理部分的头指针,tail:待处理部分的尾指针

    # 返回条件

    if head == tail or m <= 0:

        return astr

    p1=head

    p2=head+m

    #1、左旋:对于字符串abc def ghi gk,

    #将abc右移到def ghi gk后面,此时n = 11,m = 3,m’ = n % m = 2;

    #abc def ghi gk -> def ghi abc gk

    k = (n - m) - n % m   #p1,p2移动距离,向右移六步

        #---------------------

        #解释下上面的k = (n - m) - n % m的由来:

        #以p2为移动的参照系:

        #n-m 是开始时p2到末尾的长度,n%m是尾巴长度

        #(n-m)-n%m就是p2移动的距离

        #比如 abc def efg hi

        #开始时p2->d,那么n-m 为def efg hi的长度8,

        #n%m 为尾巴hi的长度2,

        #因为我知道abc要移动到hi的前面,所以移动长度是

        #(n-m)-n%m = 8-2 = 6。

        #*/

    i=0

    while i<k:

        astr[p1],astr[p2]=astr[p2],astr[p1]

        i+=1

        p1+=1

        p2+=1

        # print (i,p1,p2)

    print (astr,n-k,n,m,p1,p2,head,tail)

    return rightRotate(astr, n - k, n % m, p1, tail)  #结束左旋,下面,进入右旋

def rightRotate(astr,n,m,head,tail):

    if head == tail or m <= 0:

        return astr

    #2、右旋:问题变成gk左移到abc前面,此时n = m’ + m = 5,m = 2,m’ = n % m 1;

    #abc gk -> a gk bc

    p1 = tail

    p2 = tail - m

    #p1,p2移动距离,向左移俩步

    k = (n - m) - n % m;

    i=0

    while i<k:

        astr[p1],astr[p2]=astr[p2],astr[p1]

        i+=1

        p1-=1

        p2-=1

    print (astr,n-k,n,m,p1,p2,head,tail)

    return leftRotate(astr, n - k, n % m, head, p1)#再次进入上面的左旋部分,

    #3、左旋:问题变成a右移到gk后面,此时n = m’ + m = 3,m = 1,m’ = n % m = 0;

    #a gk bc-> gk a bc。 由于此刻,n % m = 0,满足结束条件,返回结果。

'''

   1、对于正整数m、n互为质数的情况,通过以下过程得到序列的满足上面的要求:

 for i = 0: n-1

      k = i * m % n;

 end

    举个例子来说明一下,例如对于m=3,n=4的情况,

        1、我们得到的序列:即通过上述式子求出来的k序列,是0, 3, 2, 1。

        2、然后,你只要只需按这个顺序赋值一遍就达到左旋3的目的了:

    ch[0]->temp, ch[3]->ch[0], ch[2]->ch[3], ch[1]->ch[2], temp->ch[1]; (*)

    ok,这是不是就是按上面(*)式子的顺序所依次赋值的序列阿?哈哈,很巧妙吧。当然,以上只是特例,作为一个循环链,相当于rotate算法的一次内循环。

2、对于正整数m、n不是互为质数的情况(因为不可能所有的m,n都是互质整数对),那么我们把它分成一个个互不影响的循环链,

所有序号为 (j + i * m) % n(j为0到gcd(n, m)-1之间的某一整数,i = 0:n-1)会构成一个循环链,一共有gcd(n, m)个循环链,对每个循环链分别进行一次内循环就行了。

    综合上述两种情况,可简单编写代码如下:

//④ 所有序号为 (j+i *m) % n (j 表示每个循环链起始位置,i 为计数变量,m表示左旋转位数,n表示字符串长度),

//会构成一个循环链(共有gcd(n,m)个,gcd为n、m的最大公约数),

//每个循环链上的元素只要移动一个位置即可,最后整个过程总共交换了n次

//(每一次循环链,是交换n/gcd(n,m)次,共有gcd(n,m)个循环链,所以,总共交换n次)。

void rotate(string &str, int m)

{

    int lenOfStr = str.length();

    int numOfGroup = gcd(lenOfStr, m);

    int elemInSub = lenOfStr / numOfGroup;

    for(int j = 0; j < numOfGroup; j++)

        //对应上面的文字描述,外循环次数j为循环链的个数,即gcd(n, m)个循环链

    {

        char tmp = str[j];

        for (int i = 0; i < elemInSub - 1; i++)

            //内循环次数i为,每个循环链上的元素个数,n/gcd(m,n)次

            str[(j + i * m) % lenOfStr] = str[(j + (i + 1) * m) % lenOfStr];

        str[(j + i * m) % lenOfStr] = tmp;

    }

}

'''

## 根据上面的描述,写出算法3

def moveGcd(astr,m):

    lenS=len(astr)

    numOfGroup=gcd(lenS,m)

    elemInSub=lenS//numOfGroup

    for j in range(numOfGroup):

        #对应上面的文字描述,外循环次数j为循环链的个数,即gcd(n, m)个循环链

        temp=''

        for  i in range(elemInSub - 1):

            #内循环次数i为,每个循环链上的元素个数,n/gcd(m,n)次

            astr[(j + i * m) % lenS] = astr[(j + (i + 1) * m) % lenS]

        astr[(j + i * m) % lenS] = temp

    return  astr

def test3_1():

    astr='helloworld'

    print (leftRotate(list(astr),10,3,0,9))

    print (moveGcd(list(astr),3))

########################################################################

##                      编程之美3.2 电话号码对应英语单词                 ##

########################################################################

########################################################################

##                      编程之美3.3 计算字符串的相似度                   ##

########################################################################

# 编辑距离的问题a,b的距离=min(F(a[1:],b[:],F(a[:],b[1:],F(a[1:],b[1:])+1

class Memoize:

    def __init__(self, f):

        self.f = f

        self.memo = {}

    def __call__(self, *args):

        if not args in self.memo:

            self.memo[args] = self.f(*args)

        return self.memo[args]

def findMinDistance(a,b,aBegin,aEnd,bBegin,bEnd):

    if aBegin>aEnd:

        if bBegin>bEnd:

            return 0

        else:

            return bEnd-bBegin+1

    if bBegin>bEnd:

        if aBegin>aEnd:

            return 0

        else:

            return aEnd-aBegin+1

    if(a[bBegin]==b[bBegin]):

        return findMinDistance(a,b,aBegin+1,aEnd,bBegin+1,bEnd)

    else:

        t1=findMinDistance(a,b,aBegin+1,aEnd,bBegin+2,bEnd)

        t2=findMinDistance(a,b,aBegin+2,aEnd,bBegin+1,bEnd)

        t3=findMinDistance(a,b,aBegin+2,aEnd,bBegin+2,bEnd)

        return min(t1,t2,t3)+1

def test3_3():

    f=Memoize(findMinDistance)

    print(f('hello','world',0,4,0,4))

########################################################################

##                      编程之美3.4 无头单链表中删除节点                  ##

########################################################################

# 很巧妙的方法A->B->C->D

# 要删除B直接删除不行,因为A->这个链会被切断,那么要做的就是既能保留这个链,又能把B给

# 删除了,做法是先把C和B的数据互换,然后删除C,接上next链,B->next=C->next即可

########################################################################

##                      编程之美3.5 最短摘要的生成                      ##

########################################################################

# 即找最短包含子列表

# 使用双指针法,首尾指针移动

def isAllExisted(sourceList,targetlist,pBegin,pEnd):

        ret=True

        for item in targetlist:

            ret=ret and sourceList[pBegin:pEnd].count(item)!=0

        return ret

def findMinLengthSub(sourceList,targetlist):

    pBegin = 0                         # 初始指针

    pEnd = 0                           # 结束指针

    nTargetLen = 99999                      # 目标数组的长度为N

    nAbstractBegin = 0              # 目标摘要的起始地址

    nAbstractEnd = 0              # 目标摘要的结束地址

    while True:

    # 假设包含所有的关键词,并且后面的指针没有越界,往后移动指针

        while pEnd <len(sourceList) and not isAllExisted(sourceList,targetlist,pBegin,pEnd):

            pEnd+=1

     # 假设找到一段包含所有关键词信息的字符串

        while isAllExisted(sourceList,targetlist,pBegin,pEnd):

            if pEnd-pBegin < nTargetLen:

                nTargetLen = pEnd-pBegin

                nAbstractBegin = pBegin

                nAbstractEnd = pEnd-1

            pBegin+=1

        if pEnd >= len(sourceList):

            break

    return nTargetLen,nAbstractBegin,nAbstractEnd

def test3_5():

    f=Memoize(findMinDistance)

    print(findMinLengthSub(["ab","ef","cd","gh","ij","k","c","ef","t","ij","yz"],['ef','ij']))

########################################################################

##                   编程之美3.7 判断两个链表是否相交                     ##

########################################################################

# 方法较多 见http://blog.163.com/song_0803/blog/static/4609759720120910373784/

# 1.用hash表 2.第一条链遍历的时候标记每一个节点,第二条中有标记过的就相交(实质同1)

# 3.把其中一条首尾相连,那么另一条有环则相交  4.看两条链最后一个节点是否相同

# 求出这个交点呢?上面的方法1,2还可以使用但是需要另外的空间

#另一种方法 5.相遍历一遍两条链发现长度为a,b a>b,那么第二次遍历的

#             时候第一条先走a-b步,然后同时走,一边比较每一个节点

########################################################################

##                   编程之美3.8 队列中取最大值问题                      ##

########################################################################

# O(1)内完成,enqueue,dequeue,findmax操作,做法是使用双数组,同步更新

########################################################################

##                  编程之美3.9 求二叉树中节点的最大距离                ##

########################################################################

#简单的递归,最大距离是一个节点左右深度最大深度子树之和+1

#同时返回深度和最大距离

def findMaxDistance(root):

    if root==None:

        return 0,0

    distanceL,heightL=findMaxDistance(root.left)

    distanceR,heightR=findMaxDistance(root.right)

    return heightL+heightR+1,max(heightL,heightR)+1

#            10

#         /      \

#       5        12

#       /\

#      4  7

def Test3_9():

    pNode10 = BSTreeNode(10);

    pNode5 = BSTreeNode(5)

    pNode12 = BSTreeNode(12)

    pNode4 = BSTreeNode(4)

    pNode7 = BSTreeNode(7)

    ConnectTreeNodes(pNode10, pNode5, pNode12)

    ConnectTreeNodes(pNode5, pNode4, pNode7)

    print (findMaxDistance( pNode10))

if __name__=='__main__':

    Test3_9()
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息