python算法1-复杂度+递归+查找+排序+高精度+前缀和+双指针

介绍

算法:计算过程,解决问题的方法
程序=算法+数据结构(动态+静态)

时间复杂度

时间复杂度

原因:因为计算机的运行效率、事件处理的复杂度不同,不能精确的判断每个程序使用的时间,所以需要时间复杂度O()进行估算、比较快慢
*比较量级(只要未达到质的变化)

O(logn):运算规模每次减半

常见的时间复杂度排序:
O(1)<O(logn)<O(n)<O(nlogn)<O(n2)<O(n2logn)<O(n3)

快速判断时间复杂度

1、确定问题规模n
2、若有循环减半过程–>logn
3、k层关于n的循环–>nk
若情况复杂要根据代码的执行过程判断

递归与汉诺塔问题

递归特点

1、调用自身
2、结束条件

关注func3和func4:
请添加图片描述
若先调用递归再进行打印,则最开始传入的数据被压在最后打印

hanoi


hanoi函数编写的底层思路。函数是一种方法;递归则是多次调用方法。

`def hanoi(n,a,b,c):#将n个盘子从a通过b移动到c
    if n>0:
        hanoi(n-1,a,c,b)
        print("moving from %s to %s "%(a,c))
        hanoi(n-1,b,a,c)

hanoi(3,'A','B','C')
` 

列表查找

内置列表查找函数:index()

str.index(substring, beg=0, end=len(string))

输入列表、带查找元素;输出元素下标(未找到时返回None或-1)

顺序查找(Linear Search)

# 线性搜索
def Linear_Search(li,val):#在列表li中查找元素val
    for ind,v in enumerate(li):#enmerate同时获取元素和索引
        if v == val:
            return ind
    else:
        return None
# 测试
def main():
    lst = ['a','b','c']
    result = Linear_Search(lst,'c')
    print(result)
main()

时间复杂度:O(n)

二分查找(Binary Search)

即折半查找;从有序列表的初始候选区li[0:n}开始,通过对待查找的值与中间值的比较。
内置列表排序函数:sort()

def Binary_Search(li,val):
    left = 0
    right = len(li) - 1
    while left <= right:
        mid = (left + right) // 2
        if li[mid] == val:
            return mid
        elif li[mid] < val:
            left = mid + 1
            # continue 
            # 当pyhton没有执行到分支末尾时会自导执行下一次循环迭代
        else:
            right = mid - 1
    else:# 没找到
        return None

时间复杂度:O(logn)

排序

快速排序

1、确定分界点:最左、最右、中间、随机
2、分界点归位:左边的所有数都比分界点小,右边的数都比数大
3、递归处理左右两端

def Quick_Sort(data,left,right):
    if left < right:#递归终止条件
        mid = partition(data,left,right)#把所选的分界点归位
        Quick_Sort(data,left.mid - 1)#递归折半搜索左边
        Quick_Sort(data,mid + 1,right)

def partition(li,left,right):
    tmp = li[left] # 切片时位置不一定是列表最左边
    while left < right: #因为当左右重合时就是归位点
        while left<right and li[right] >= tmp:#在右边找比tmp小的数
            right -= 1 #往左走
        li[left] = li[right]
        while left < right and li[left] <=tmp:
            left += 1
        li[right] = li[left]
    li[left] = tmp
    return left

li = [3,4,6,7,8,2,1,0]
Quick_Sort(li,0,len(li)-1)

时间复杂度:O(nlogn)
问题:
1、最坏的情况:完全倒序,每次至少一个数 O()
2、递归

归并排序

sort()

def merge(li,low,mid,high):
    i = low
    j = mid + 1
    litmp = []
    while i <= mid and j <= high:#只要左右两边都有数
        if li[i] < li[j]:
            litmp.append(li[i])
            i += 1
        else:
            litmp.append(li[j])
            j += 1
    #while执行完,肯定有一部分没数了
    while i <= mid:
        litmp.append(li[i])
        i += 1
    while j <= high:
        litmp.append(li[j])
        j += 1

    li[low:high+1] = litmp
    return li

def merge_sort(li,low,high):
    if low < high:#至少有两个元素,递归
        mid = (low + high) // 2
        merge_sort(li,low,mid)
        merge_sort(li,mid+1,high)
        merge(li,low,mid,high)

桶排序

def bucket_sort(li,maxnum):
    bucket_count = 100 # 创建桶的数量
    buckets = [[] for _ in range(bucket_count)] # 创建bucket_count个桶

    #放数进桶
    for i in li:
        index = int((i/maxnum)*(bucket_count-1)) # 线性映射计算位置
        buckets[index].append(i) # 在选定桶里放入元素

    #桶内排序
    for bucket in buckets:
        bucket.sort()

    #合并桶
    sorted_arr = []
    for bucket in buckets:
        sorted_arr.extend(bucket)
    return sorted_arr

import random
li = [random.randint(0,10000) for i in range(100000)]
print(li[:10])
sorted_li = bucket_sort(li,max(li))
print(sorted_li[:10])

高精度

关键:利用decimal库(结果保留多位小数)和Fraction库(分数计算)

Fraction:保留分数计算
可以同时提供分子(numerator)和分母(denominator)给构造函数用于实例化Fraction类,但两者必须同时是int类型或者numbers.Rational类型,否则会抛出类型错误。当分母为0,初始化的时候会导致抛出异常ZeroDivisionError。
decimal:保留高精度小数

import decimal
from fractions import Fraction
decimal.getcontext().prec = 200 # 设置decimal精度为200
n1 = Fraction(2,7)
n2 = Fraction(3,2)
#利用fraction函数避免在计算中的精度丢失
c = n1/n2
#fraction无法直接丢进dicimal计算,转化为除法
c2 = decimal.Decimal(c.numerator)/decimal.Decimal(c.denominator)
print("分数形式:",c)
print("精度200小数:",c2)

前缀和算法

关键:创建字典保存循环时看似无用的和。

思想:利用上述关键点和减法,省略了在暴力枚举中对中段数组数值的重复运算,使得算法更加简洁。
eg.求和为k的子数组:

def SubarraySum(nums,k):
    cur_sum = 0
    dict = {} # 用于存储在计算时出现的和的个数
    dict[0] = 1 # 出现cur_sum - k = 0的情况
    count = 0
    for num in nums:# 遍历数组并加和
        cur_sum += num 
        if (cur_sum - k) in dict: # 判断数组间是否有差为所求k
            count += dict[cur_sum-k]
        if cur_sum in dict:# 不管上个if有没有满足,数组加和都要进行存储
            dict[cur_sum] += 1
        else:
            dict[cur_sum] = 1
    return count

差分算法

双指针算法

关键:

  1. 初始值
  2. 遍历终止条件
  3. 左右指针的变化规则
1、二分查找
2、两数之和
3、不重复最长字串
# 求不重复最长字串长度
def max_long_str(s):
    left = right = 0
    s = list(s)
    max_len = 0
    while(right != len(s)):
        right += 1
        while(len(s[left:right+1]) > len(set(s[left:right+1]))):
            left += 1
            s.pop(0)
        max_len = max(max_len,right-left+1)
    return max_len
  • 14
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值