数据结构与算法之排序和基础算法

基础算法

一、排序

1.冒泡排序

n=int(input())
a = list(map(int,input().split())
for i in range(n-1):
    for j in range(i,n):
         if a[i]>a[j]:
          a[i],a[j]=a[j],a[i]

[宝藏排序1](蓝桥杯省赛无忧班(Python 组)第 3 期 - 宝藏排序I - 蓝桥云课 (lanqiao.cn))

2.选择排序

从左往右不断的找最小的值,往前交换

n = int(input())
a = list(map(int,input().split()))
for i in range(n-1):
    min_value = a[i]
    min_idx = i
    for j in range(i,n):
        if a[j]<min_value:
            min_value = a[j]
            min_idx = j
    a[min_idx],a[i] = a[i],a[min_idx]
print(' '.join(map(str,a)))

[宝藏排序1](蓝桥杯省赛无忧班(Python 组)第 3 期 - 宝藏排序I - 蓝桥云课 (lanqiao.cn))

3.插入排序

从后往前找牌看看插到前面哪里好,就和打扑克牌边打牌边捯饬牌一样

n = int(input())
a = list(map(int,input().split()))
for i in range(1,n):
    value = a[i]
    insert_idx = 0
    for j in range(i - 1,-1,-1):
        if a[j] > value:
            a[j+1]=a[j]
        else:
            insert_idx = j+1
            break
    a[insert_idx] = value  

宝藏排序1

4.快速排序

  1. 设置基准下标,把比下标大的和小的分出来

  2. 左右递归排序

def partition(a,left,right):
    idx = left+1
 for i in range(left+1,right+1):
        if a[i]<=a[left]:
            a[i],a[idx]=a[idx],a[i]
            idx += 1
    a[left],a[idx-1] = a[idx-1],a[left]
def quicksort(a,left,right):
    if left<right:
        mid = partition(a,left,right)
        quicksort(a,left,mid-1)
        quicksort(a,mid+1,right)

5.归并排序

  1. 合并两个有序的列表

def Merge(A,B):
    result = []
    while len(A) != 0 and len(B) != 0:
        if A[0] <= B[0]:
            result.append(A.pop(0))
        else:
            result.append(B.pop(0))
    result.extend(A)
    result.extend(B)
    return result
  1. 归并排序的步骤
    • 把数组分成两部分

    • 每部分递归处理变有序

    • 将两个有序的列表合并起来

def MergeSort(A):
    if len(A)<2:
        return A
    mid = len(A) // 2
    left = MergeSort(A[:mid])
    right = MergeSort(A[mid:])
    return Merge(left,right)

6.桶排序

image-20240227210415300

image-20240227210415300

def   Bucket_Sort(a,bucketcount):
    minvalue,maxvalue = min(a),max(a)
    bucketsize = (maxvalue - minvalue + 1) // bucketcount
    res = [[] for _ in range(bucketcount + 1)]
    for x in a:
        idx = (x-minvalue) // bucketsize
        res[idx].append(x)
    ans=[]
    for res_x in res:
        res_x.sort()
        ans += res_x
    retuen ans

7.经典练习

二、基础算法

1.枚举

逐个尝试所有可能的值来解决问题

2.模拟

——按题目含义模拟就行,一般不涉及算法

  1. 读懂题

  2. 代码和步骤一一对应

  3. 把重复的部分写成函数

  4. 按顺序写

无尽的石头

ef next_step(x):
  x = str(x)
  next = 0
  for i in range(len(x)):
    next += int(x[i])
  return next + int(x)
t = int(input())
result = []
for i in range(t):
  n = int(input())
  now_step = 1
  step = 0
  while now_step < n:
    now_step = next_step(now_step)
    step += 1
  if now_step == n:
    result.append(step)
  else:
    result.append(-1)
for i in range(len(result)):
  print(result[i])

小兰和小巧的挑战

t = int(input())
ts = []
for i in range(t):
  n = int(input())
  a = list(map(int,input().split()))
  count = 0
  number1 = 0
  number2 = 0
  for j in range(n):
    if a[j] < 0:
      number1 += a[j]
    elif a[j] > 0:
      number2 += a[j]
    else:
      count += 1
  if number2+count+number1==0:
    ts.append(count+1)
  else:
    ts.append(count)
for i in range(len(ts)):
  print(ts[i])

DNA序列修正(答案不是全对)

import os
import sys
import math

# 请在此输入您的代码
def judge(a,b):
  if a=='A' and b=='T' or a=='T' and b=='A' or a=='C' and b=='G' or a=='G' and b=='C':
    return True
  else:
    return False
N = int(input())
D1 = input()
D2 = input()
D3 = []
D4= []
D5 = []
count = 0
for i in range(N):
  if judge(D2[i],D1[i]):
    continue;
  else:
    if D1[i]==D2[i]:
      D3.append(D1[i])
    else:
      D4.append(D1[i])
      D5.append(D2[i])
A=D3.count('A')
T=D3.count('T')
C=D3.count('C')
G=D3.count('G')
length=len(D4)
for i in range(len(D4)):
  for j in range(len(D5)):
    if judge(D4[j],D5[j])!=True:
      if judge(D4[i],D5[j])==True and judge(D4[j],D5[i])==True:
        D5[i],D5[j] = D5[j],D5[i]
        length-=2
        count+=1
        break
count+=abs(A-T)+abs(C-G)+min(A,T)+min(C,G)+count+length
print(int(count))

3.递归

  1. 自己调用自己

  2. 把大型复杂问题转为一个与原问题相似规模较小的问题

  3. 注意点:

    • 写出口

    • 将问题转为子问题

  4. 例子:阶乘

    def f(n):
        if n<=1:
            return 1
        ans = n * f(n-1)
        return ans
    
  5. image-20240228175443069

    image-20240228175443069

    def move(n,A,B,C):
        if n == 0:
            return
        #从A到B
        move(n-1,A,B,C)
        #从B到C
        move(n-1,B,A,C)
    

4.进制转换

  1. 基数:表示基本数字符号的个数

  2. 权:每个数字每位表示的数值 权=基数^x

  3. 按权展开法:11011=1^4+1^3.......

  4. 把K进制的数字转换为10进制的

    int_to_char = '0123456789ABCDEF'
    char_to_int = {}
    for idx,chr in enumerate(int_to_char):
        char_to_int[chr] = idx
    def K_To_Ten(k,x):
        ans = 0
        #翻转x
        x=x[::-1]
        for i in range(len(x)):
         ans = ans + char_to_int[x[i]] * k ** i
       return ans
    
  5. 十进制转其他(整数)

    image-20240228193116388

    转小数

    image-20240228193407280

    image-20240228193407280

    int_to_char = '0123456789ABCDEF'
    char_to_int = {}
    for idx,chr in enumerate(int_to_char):
        char_to_int[chr] = idx
    def Ten_to_K(k,x):
        ans = ''
        while x!=0:
            ans += int_to_char[x % k]
            x//=k
       return ans[::-1]
    

5.前缀和

  1. sum[i] = sum[i-1] + a[i]

  2. 能快速计算出区间

    a[i] + a[i+1] + ... + a[j] = sum[j] - sum[i-1]

    把复杂度从O(n)优化到了O(1)

6.差分

——提升修改的效率

  1. image-20240228194406039

    image-20240228194406039

    a[k] = d[1] + d[2] + ... + d[k]

    a[]是D[]的前缀和

  2. 差分是前缀和的逆运算

  3. 尺取法:两个for循环变成一个,前提是两个变量之间是有关系的

  4. 习题:统计子矩阵

    n,m,k=map(int,input().split())
    a = [[0] for i in range(n)]
    a.insert(0,0*(m+1))
    for i in range(1,n+1):
        a[i].extend(map(int,input().split()))
    s = [[0]*(m+1) for i in range(n+1)]
    for i in range(1,n+1):
        for j in range(1,m+1):
            s[i][j] = s[i-1][j] + a[i][j]
    ans = 0
    for i1 in range(1,n+1):
        for i2 in range(i1,n+1):
            j1=1;z=0
            for j2 in range(1,m+1):
                z += s[i2][j2] - s[i1-1][j2]
                while z>k:
                    z -= s[i1][j1] - s[i1-1][j1]
                    j1 += 1
                ans += j2-j1+1
    print(ans)
    

7.离散化

  1. 不关注数字本身,只关注大小关系,利用排名代替原数据

  2. 仅关注偏序的题都可以用离散化

  3. 步骤:

    image-20240228194735069

    image-20240228194735069

    def Discrete(a):
        #去重,排序
        b = list(ser(a))
        b.sort()
        dic = dict(zip(b,list(range(len(b)))))
        ans = []
        for x in a:
            ans.append(dic[x])
         return ans
    

8.贪心

  1. image-20240228200123270

    image-20240228200123270

  2. 并不是所有的局部最优可以是全局最优

  3. 如何判断贪心:

    image-20240228200611888

    image-20240228200611888

  4. 经典习题

    • [ ]

      image-20240228200938176

      #导入堆的库
      import heapq
      n = int(input())
      a = list(map(int,input().split()))
      #堆:每次获取最小的元素,添加元素
      #1. 把a转换成堆
      heapq.heapqify(a)
      ans = 0
      while len(a) >= 2:
       x = heapq.heappop(a)
          y = heapq.heappop(a)
          heapq.heappush(a,x+y)
          ans += x+y
      
      • [ ]

        image-20240228202714546

        w = int(input())
        n = int(input())
        a = []
        for i in range(n):
            a.append(int(input))
        #1.排序
        a.sort()
        #最小的和最大的下标
        l,r = 0,n - 1
        ans = 0
        while True:
            if l==r:
                ans+=1
                break
            if l>r:
                break
            if a[l] + a[r] <= w:
                ans+=1
                l+=1
                r-=1
            else:
                ans+=1
                r-+1
         print(ans)
        

        最大卡牌价值

        n,k = map(int,input().split())
        a = list(map(int,input().split()))
        b = list(map(int,input().split()))
        cha = []
        for i in range(len(a)):
          if b[i] - a[i] >0:
            cha.append(b[i] - a[i])
        cha.sort(reverse=True)
        result = sum(a)
        if k >= len(cha):
          result += sum(cha)
        else:
          for i in range(k):
            result += cha[i]
        print(result)
        

        最小战斗力差距

        n = int(input())
        w = list(map(int,input().split()))
        result = 1000000
        w.sort()
        i,j=0,1
        while j<len(w):
          cha = abs(w[j]-w[i])
          if cha < result:
            result=cha
          j+=1
          i+=1
        print(result)
        

9.双指针

  • [ ] 反向扫描

  • [ ] 滑动窗口

    n,S = map(int,input().split())
    a = list(map(int,input().split()))
    min_len() = n + 1
    left,right=0,0
    tot = 0
    while left < n:
        #不断扩展右端点,直到区间和>S
        while right < n and tot < S:
            tot += a[right]
            right += 1
        if tot >= S:
            min_len = min(min_len,right-left)
        #左端点往右走
        tot -= a[left]
        left += 1
     if min_len == n+1:
        min_len=0
     print(min_len)
    

10.二分

  1. 每次将搜索范围缩小一半

  2. 二分的前提条件:单调性

  3. 步骤

    • 找到区间

    • 不断循环,直至区间满足特定的条件:计算中点或者随时调整

  4. bitsect模块(二分)

    • insort_right(a,x)插入

    • bisect_right(a,x)查找

  5. 二分答案

    image-20240229190645784

    image-20240229190645784

    image-20240229190904925

    image-20240229190904925

11.倍增(快速幂)

  1. 高效求指数幂,基于分治的思想,通过反复求平方来实现快速计算指数幂处理二分,公共祖先

12.构造

  1. 通过观察规律和结构来解决方法

13.位运算

  1. 位运算:对二进制进行操作的运算方式

    • 与运算:有0得0

    • 或运算:有1得1

    • 异或运算:相同为0,不同为1(考的概率大)^

    • 取反 ~

    • 左移,右移 << >>

      每次向左移相当于×2,空缺的位置补0

      每次右移相等于➗2,空缺的位置补0

  2. 位运算的技巧

    image-20240229201002004

    image-20240229201002004

  • 22
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值