蓝桥杯(python) 备赛 Day2(基础算法)

1.双指针

在区间操作时,利用两个下标同时便利,进行高效操作,可将O(n2)时间降低到O(n)

根据指针移动的方向,分为反向扫描同向扫描

反向扫描

    一般用于有序数组或者字符串类问题

对于有序数组,见我day1文章中的“纪念品分组”一题的解题思路,运用的就是反向扫描思想

对于字符串一类, 对应题目:回文判断

​#方法一(使用双指针的思想)
import os
import sys

s=input()
l,r=0,len(s)-1
ok='Y'
while l<=r:
  if s[l]==s[r]:
    l+=1
    r-=1
  else:
    ok='N'
    break
print(ok)

#方法二(直接翻转字符串)
s=input()
if s==s[::-1]:
  print('Y')
else:
  print('N')


​

同向扫描

被称为滑动窗口,根据题给条件,维护一个[left,right]区间的信息,如区间和,各个元素个数,直至满足条件时停止滑动

对应题目1:美丽的区间

import os
import sys

n,S=map(int,input().split())

a=list(map(int,input().split()))
#找最短区间满足区间之和>=S
min_len=n+1
#[left,right)
left,right=0,0
#tot表示滑动窗口【left,right)之间的区间和
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)

对应题目2:挑选子串

import os
import sys

n,m,k=map(int,input().split())
a=list(map(int,input().split()))
ans=0
left,right=0,0
num=0
#num表示滑动窗口中大于等于m的元素个数

while left<n:
  #不断扩展右端点,直至区间恰好有k个数字
  while num<k and right<n:
    if a[right]>=m: 
      num+=1
    right+=1
    
  if num>=k:
    ans+=(n-right+1)
    
  #直接在原来的num上进行计算
  if a[left]>=m:
    num-=1
  left+=1

print(ans)

2.二分

  二分法

每次将搜索的范围缩小一半,可以在O(log n)实时间内找到正确答案

二分法的前提条件:具有单调性(利用单调性调整二分算法查找的区间)

步骤:

1.选取候选区间[left,right]

2.不断循环,直至区间满足特定条件

     ——计算中点mid=(left+right)/2

     ——判断中点是否合法,根据中点的计算结果调整[left,right]

  浮点二分

eg.计算根号2
 

left,right=1,2

while (right-left)>=1e-5:
  mid=(left+right)/2

  if mid*mid>2:
    right=mid
  else:
    left=mid

  二分答案

题目所求答案(一般为整数)具有单调性质,采用猜答案+二分

步骤:

#二分答案 半伪代码
def check(x):
  #判断x是否合法,合法返回True,否则返回False
  pass

left,right,ans=初始化

while left<=right:
  mid=(left+right)//2
  if check(mid):
    ans=mid
    left=mid+1
  else:
    right=mid-1
print(ans)

相关题目1:分巧克力

import os
import sys

N,K=map(int,input().split())
a=[]
for i in range(N):
  x,y=map(int,input().split())
  a.append((x,y))

#合法条件:假定切出的巧克力边长为x,能否切出x块
def check(x):
  #cnt表示能切出的块数
  cnt=0
  for H,W in a:
    cnt+=(H//x)*(W//x)
  return cnt>=K

#边长搜索区间为[left,right]
left,right=1,100000
ans=1
while left<=right:
  mid=(left+right)//2
  if check(mid):
    ans=mid
    left=mid+1
  else:
    right=mid-1

print(ans)

 相关题目二:跳石头

import os
import sys
#演示下标                    #最短跳跃距离
#0,2,11,14,17,21,25,=》 2
#
#0,11,14,17,21,25    =》3
L,N,M=map(int,input().split())
a=[]
for i in range(N):
  d=int(input())
  a.append(d)

#假设最短跳跃距离为x,移除的岩石数量不超过M,则为合法
def check(x):
  #cnt 表示移除岩石的数量
  cnt=0
  #;ast_idx表示上一个位置
  last_idx=0
  for i in range(N):
    if a[i]-last_idx>=x:
      last_idx=a[i]
    else:
      cnt+=1
  #最后一步的特判
  if L-last_idx<x:
    return False
  return cnt<=M 


left,right=1,L
ans=-1
while left<=right:
  mid=(left+right)//2
  if check(mid):
    ans=mid
    left=mid+1
  else:
    right=mid-1

print(ans)

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值