zoukankan      html  css  js  c++  java
  • python算法

    引言

    定义:算法就是按照一系列有限的步骤正确解决问题的办法
    属性:

    • 正确:就是可以正确的求解问题
    • 快速:就是时间复杂度要尽量小
    • 有穷性:要在有限个步骤解决问题
    • 简洁
    • 通用

    渐进分析法为什么可以做到与算法运行硬件环境无关?

    算法分析时往往假设输入规模n足够大,甚至趋近于无穷大。这样的假设,意味着我们关注的是算法运算时间的增长率,也就是,随着输入规模n的增长,T(n)的增长率。当n趋向于无穷大时,决定T(n)增长率的便是T(n)中的高次项,从而可以忽略T(n)中的低次项以及高次项前的常数项。这些低次项或者高次项前的常数项,往往是机器性能、程序设计语言的性能和编译器性能等因素产生,而这些在算法时间复杂度分析中都是需要略去的次要因素。

    为什么说多项式时间复杂度的算法要优于指数时间复杂度的算法?

    在这里插入图片描述

    渐进分析与python模型

    二分搜索

    def binary_search(A,k):
        first=0
        last= len(A)-1 
        found=False
        while first<=last and not found:
            midpoint=(first+last)//2
            if A[midpoint]==k: 
                found=True
            else:
                if k < A[midpoint]:
                    last=midpoint-1 
                else:
                    first=midpoint+1
        return found
    

    确界Θ、上界Ο、下界Ω

    问题求解和代码优化

    1.动态规划算法的基本要素为最优子结构性质与重叠子问题性质

    2.能采用贪心算法求最优解的问题,一般具有的重要性质为最优子结构性质与贪心选择性质

    3.使用分治法求解不需要满足的条件是(A )。

    A 子问题必须是一样的 B 子问题不能够重复

    C 子问题的解可以合并 D 原问题和子问题使用相同的方法解

    4.矩阵连乘问题的算法可由 动态规划 设计实现。

    5..算法是由若干条指令组成的有穷序列,且要满足输入、输出、确定性和有限性四条性质。

    6.归并排序的时间复杂度是c

    (a)n (b)n^2 (c)nlgn (d)lgn

    7.下列哪个问题可以用贪心算法求解( D )D.哈夫曼编码问题

    递归算法和递归函数

    主分析法求时间复杂度

    • f(n) < nlogba,这种情况意味着,递归树上各层结点的和从根结点开始依次递增,由于渐进表示可以去掉低次项,因此得T(n)=Θ(nlogba)。
    • f(n) = nlogba,k是大于等于0的常数。这种情况意味着,递归树上各层结点的和从根结点开始并没有显著变化,因此得 T(n)=Θ( nlogba*logn)
    • f(n) > nlogba,同时对于常数c<1满足af(n/b)≤cf(n)。这种情况意味着,递归树上各层结点的和从根结点开始依次递减,因此得T(n)=Θ(f(n)。

    img

    给定正整数N,计算所有长度为N但没有连续1的二分字符。比如,N=2时,输

    出为[00,01,10]:当N=3时,输出为1000,001,010,100,101。

    import math
    
    N = int(input("输入N:"))
    
    def ss(a):
        a = bin(a)[2:]
        j = 6
        for i in a:
            if j == i == '1':
                return False
            j = i
        return True
    
    def printN(a, N):
        a = bin(i)[2:]
        while len(a) < N:
            a = '0' + a
        print(a)
    
    
    for i in range(int(math.pow(2,N))):
        if ss(i):
            printN(i,N)
    

    统计逆序数问题

    #_*_coding:UTF-8_*_
    
    import random
    
    
    #逆序计算的简单算法
    def count_inversions_simple(A):
        inv_count = 0
        inv_list = []
        for i in range(len(A)):
            for j in range(i, len(A)):
                if A[i] > A[j]:
                    inv_count += 1
                    inv_list.append([A[i],A[j]])
        return inv_count, inv_list
    
    
    #逆序计算的分治算法   边排序边找逆序数
    #类似归并排序,加入了逆序数计算 T(n) = 2T(n/2) + O(n) = O(nlogn)
    def count_inversions_dc(A):
        if len(A) <= 1:        #边界条件
            return 0, A
        middle = len(A) // 2
        leftA = A[:middle]
        rightA = A[middle:]
        countLA, leftA = count_inversions_dc(leftA)
        countRA, rightA = count_inversions_dc(rightA)
        countLRA, mergedA = merger_and_count(leftA,rightA)
        return countLA + countRA + countLRA, mergedA
    
    
    #前提:输入的A,B是有序的 
    def merger_and_count(A,B):
        i, j, inv_count = 0, 0, 0
        alist = []
        while i < len(A) and j < len(B):
            if A[i] < B[j]:
                alist.append(A[i])
                i += 1
            else:            # A[i] > B[j] 则B[j]与A右边所有元素构成逆序
                inv_count += len(A) - i
                alist.append(B[j])
                j += 1
        while i < len(A):
            alist.append(A[i])
            i += 1
        while j < len(B):
            alist.append(B[j])
            j += 1
        return inv_count, alist
    
    
    
    def main():
        list = [random.randint(1,10) for x in range(10)]
        sum, alist = count_inversions_dc(list)
        print(str(list))
        print("逆序数:"+str(sum)+",排序后: "+str(alist))
        
    
    
    if __name__ == '__main__':
        main()
    
    
    

    第k小的数

    方法一(课本):

    #_*_coding:utf-8_*_
    
    import random
    
    def select_fct(array, k):
        if len(array) <= 10:
            array.sort()
            return array[k]
        pivot = get_pivot(array)
        array_lt, array_gt, array_eq = patition_array(array, pivot)
        if k < len(array_lt):
            return select_fct(array_lt, k)
        elif k < len(array_lt) + len(array_eq):
            return array_eq[0]
        else:
            normalized_k = k - (len(array_lt) + len(array_eq))
            return select_fct(array_gt, normalized_k)
    
    def get_pivot(array):
        subset_size = 5
        subsets = []
        num_medians = len(array) // subset_size
        if (len(array) % subset_size) > 0:
            num_medians += 1
        for i in range(num_medians):
            beg = i * subset_size
            end = min(len(array), beg+subset_size)
            subset = array[beg:end]
            subsets.append(subset)
        medians = []
        for subset in subsets:
            median = select_fct(subset, len(subset)//2)
            medians.append(median)
        pivot = select_fct(medians, len(subset)//2)
        return pivot
    
    def patition_array(array, pivot):
        array_lt = []
        array_gt = []
        array_eq = []
        for item in array:
            if item < pivot:
                array_lt.append(item)
            elif item > pivot:
                array_gt.append(item)
            else:
                array_eq.append(item)
        return array_lt, array_gt, array_eq
    
    
    def main():
        num = 20
        array = [random.randint(1,100) for x in range(num)]
        random.shuffle(array)         #random.shuffle(x[, random]):用于将一个列表中的元素打乱
        random.shuffle(array)
        k = 7
        print(sorted(array))
        kval = select_fct(array, k)
        print("第八小:"+str(kval))
        sorted_array = sorted(array)
        assert sorted_array[k] == kval    #python assert断言是声明其布尔值必须为真的判定,如果发生异常就说明表达示为假。
        
    if __name__ == '__main__':
        main()
    

    方法二:

    #_*_coding:utf-8_*_
    #分治法解决第k小的数
    import random
    
    def partition(nums):
        pi = nums[0]
        low = [x for x in nums[1:] if x < pi]
        high = [x for x in nums[1:] if x >= pi]
        return low, pi, high
    
    # 查找第 k 小的元素
    def solve(nums, k):
        low, pi,high = partition(nums)    #分解
        n = len(low) 
        if n+1 == k:    #k+1表示第k小
            return pi
        elif n < k:
            return solve(high,k-n-1) #减去小于和等于的
        else:
            return solve(low,k)
    
    if __name__ == '__main__':
        list = [random.randint(1,20) for x in range(20)]
        print(sorted(list))
        print(solve(list,3)) #第三小
        print(solve(list,10)) #第十小
    

    硬币找零,贪心算法

    #零钱找零,pay是应付金额
    def coin(pay):
        m = [100, 25, 10, 5, 1]
        list = []
    
        sort_m = sorted(m, reverse=True)
        for i in sort_m:
            coin_count = int(pay/i)
            list += [i,] * coin_count
            pay -= coin_count*i
            if pay <= 0:
                break
        return list
        
        
     def main():
        #硬币找零
        pay = 263
        print(coin(pay))
        
     if __name__ == "__main__":
        main()
    

    digkstra算法求单源最短路径

    #_*_coding:utf-8_*_
    #单源最短路径问题
    
    MAX_value = 999999
    
    def dijkstra(graph, s):  #s是源点,d(s) = 0
        if graph is None:    # 判断图是否为空,如果为空直接退出
            return None
        dist = [MAX_value,]*len(graph)
        dist[s] = 0
        S = []
        Q = [i for i in range(len(graph))]
        dist_init = [i for i in graph[s]]
        while Q:
            u_dist = min([d for v, d in enumerate(dist_init) if v in Q])
            u = dist_init.index(u_dist)
            S.append(u)
            Q.remove(u)
     
            for v, d in enumerate(graph[u]):
                if 0 < d < MAX_value:
                    if dist[v] > dist[u]+d:
                        dist[v] = dist[u]+d
                        dist_init[v] = dist[v]
                        print(dist[v])
        return dist    #到每一个点的最短路径距离
     
     
    if __name__ == '__main__':
        graph_list = [  [0, 9, MAX_value, MAX_value, MAX_value, 14, 15, MAX_value],
                        [9, 0, 24, MAX_value, MAX_value, MAX_value,MAX_value,MAX_value],
                        [MAX_value, 24, 0, 6, 2, 18,MAX_value,19],
                        [MAX_value, MAX_value, 6, 0, 11,MAX_value,MAX_value, 6],
                        [MAX_value,MAX_value, 2, 11, 0, 30,20, 16],
                        [14,MAX_value,18,MAX_value,30,0,5,MAX_value],
                        [15,MAX_value,MAX_value,MAX_value,20,5,0,44],
                        [MAX_value,MAX_value,19,6,16,MAX_value,44,0]]
     
        distance = dijkstra(graph_list, 0)
        print(distance)  
    

    给定n件物品的序列,以及容量为c的箱子。求将物品装入到箱子,每一个箱子装人的物品总重量不能超过箱子的容量。给出一个算法,要求用最小的箱子数将物品全部装入。

    比如有6个物品,其重量分别为[4,8,1,42,1],箱子容量c=10。那么最少需要2个箱子将物品全部装入,其中一个箱子装入[4,4,2],另一个箱子装入[8,2]

    #_*_coding:utf-8_*_
    
    def box(list, n):
        list.sort(reverse = True)
        aa = [[] for x in range(len(list))] 
    
        for element in list:
            for j in range(len(list)):
                if sum(aa[j]) + element <= n:
                    aa[j].append(element)
                    break
                  
        aa = [x for x in aa if len(x)!=0]
        return aa
    
    list = [4,8,1,4,2,1]
    print(box(list, 10))
    

    动态规划问题

    #_*_coding:utf-8_*_
    #动态规划
    import numpy as np 
    import random
    
    #斐波那契函数
    memo = {}   #字典
    def fib2(n):
        if n in memo:
            return memo[n]
        else:
            if n <= 1:
                f = 1
            else:
                f = fib2(n-1) + fib2(n-2)
            memo[n] = f
            return f
    
    def fib_bottom_up(n):
        fib = {}             #存储结果的字典
        for k in range(n+1):
            if k <= 1:
                f = 1
            else:
                f = fib[k-1] + fib[k-2]   #填表
            fib[k] = f
    
        return fib[n]
    
    
    #捡硬币
    #自底向上实现递归策略
    def bottom_up_coins(row_coins):
        table = [None] * (len(row_coins) + 1)    #申明表格
        table[0] = 0
        table[1] = row_coins[0]
        for i in range(2, len(row_coins)+1):
            table[i] = max(table[i-2] + row_coins[i-1], table[i-1])  #填表
        return table
    
    #回溯
    def trace_back_coins(row_coins, table):
        select = []
        i = len(row_coins)     #从最后一位索引
        while i >= 1:
            if table[i] > table[i-1]:
                select.append(row_coins[i-1])
                i -= 2
            else:
                i -= 1
        return select
    
    
    
    #子序列和的最大值
    def num_max(alist):    #自底向上递归
        table = [None] * (len(alist)+1)      
        table[0] = 0
        for i in range(1, len(alist)+1):
            table[i] = max(table[i-1] + alist[i-1], alist[i-1])  #计算重新开始的优劣
        return table
    
    def tract_back_subseq(alist, table):
        select = []
        ind_max = np.argmax(table)        #得到最大值索引
        while ind_max >= 1:
            if table[ind_max] == alist[ind_max-1] + table[ind_max-1]:
                select.append(alist[ind_max-1])
                ind_max -= 1
            else:
                select.append(alist[ind_max-1])
                break
        return select
    
    
    if __name__ == "__main__":
        list = [random.randint(1,20) for x in range(10)]
        print(list)
        print(fib2(10))
        print(fib_bottom_up(10))
    
        table = bottom_up_coins(list)
        print(trace_back_coins(list, table))
    
        table = num_max(list)
        print(tract_back_subseq(list, table))
        
    
    
    

    0,1 背包问题

    #_*_coding:utf-8_*_
    #0 1 背包问题
    #分析: k(i, x) = max(k(i-1, x), k(i-1, x-s) + v) 物品i放入背包,不放入背包
    
    def knapSack(W, wt, val, n):
        #W是容量, wt是物品容量,val是价值, n是物品数量
        k = [[0 for x in range(W+1)] for x in range(n+1)]
        for i in range(n+1):
            for w in range(W+1):
                if i == 0 or w == 0:     #不满足条件,物品或者容量为空
                    k[i][w] = 0
                elif wt[i-1] <= w:
                    k[i][w] = max(val[i-1] + k[i-1][w-wt[i-1]], k[i-1][w])
                else:
                    k[i][w] = k[i-1][w]
        return k
    
    if __name__ == "__main__":
        k = knapSack(10, [1,2,3], [2,3,4], 3)
        print(k)
    
    
    

    习题参考

  • 相关阅读:
    第二周作业
    求最大值及下标编程总结
    查找整数编程总结
    课程设计第一次实验总结
    第十二周作业
    第十一周作业
    第十周作业
    第九周作业
    第八周作业
    第七周作业
  • 原文地址:https://www.cnblogs.com/tomyyyyy/p/11125793.html
Copyright © 2011-2022 走看看