二分查找(有蓝桥杯配题)

1.枚举查找和二分查找的区别

枚举查找也就是顺序查找。

实现原理就是逐个比较al0.n-11中的元素,直到找出元素x或将索偏整个数组后确定义不在其中,或者说符合要求的元素在不在数组中。

最坏的情况下需要比较N次,时间复杂度是O(n)线性阶。

二分查找也就是折半查找。折半查找是将N个元素分成大致相同的两部分。选取中间元素与查找签的元素比较,或者与查找条件相比较,找到或者说找到下一次查找的半区。每次都将范围缩小至;所以时间复杂度是0(log2n),但是二分查找的前提是有序的,一般是从小到排列。折半查找的基本思想:

在有序表中(low,high,low<=high),取中间记录即[(high+low)/2]作为比较对象。

●若给定值与中间记录的关键码相等,则查找成功

● 若给定值小于中间记录的关键码,则在中间记录的左半区继续查找

● 若给定值大于中间记录的关键码,则在中间记录的右半区继续查找

不断重复上述过程,直到查找成功,或所查找的区域无记录,查找失败。

二分查找的特征:

1.答案具有单调性;

2.二分答案的问题往往有固定的问法,比如:令最大值最小(最小值最大),求满足条件的最大(小)值等。

 模板:

#在单调递增序列a中查找>=x的数中最小的一个(后推x)
while low < high:
    mid = (low + high) / 2
    if a[mid] >= x:
        high = mid
    else:
        low = mid + 1
#在单调递增序列a中查找<=x的数中最大的一个(前推x)
while low < high:
    mid = (low + high) / 2
    if a[mid] <= x:
        low = mid
    else:
        high = mid - 1

题目:跳石头

题目描述

一年一度的"跳石头"比赛又要开始了!

这项比赛将在一条笔直的河道中进行,河道中分布着一些巨大岩石。组委会已经选择好了两块岩石作为比赛起点和终点。在起点和终点之间,有 N 块岩石(不含起点和终点的岩石)。在比赛过程中,选手们将从起点出发,每一步跳向相邻的岩石,直至到达终点。

为了提高比赛难度,组委会计划移走一些岩石,使得选手们在比赛过程中的最短跳跃距离尽可能长。由于预算限制,组委会至多从起点和终点之间移走M 块岩石(不能移走起点和终点的岩石)。

输入描述

输入文件第一行包含三个整数 L,N,M,分别表示起点到终点的距离,起点和终点之间的岩石数,以及组委会至多移走的岩石数。

接下来 N 行,每行一个整数,第 i 行的整数 Di​(0<Di​<L)表示第 i 块岩石与起点的距离。这些岩石按与起点距离从小到大的顺序给出,且不会有两个岩石出现在同一个位置。

其中,0≤M≤N≤5×10^4,1≤L≤10^9。

输出描述

输出只包含一个整数,即最短跳跃距离的最大值。

输入输出样例

示例

输入

25 5 2
2
11
14
17
21

输出

4

 二分法套路题:最小值最大化、最大值最小化

在n块岩石中移走m个石头,有很多种移动方法。 在第i种移动方法中,剩下的石头之间的距离,有一个最小距离ai。 在所有移动方法的最小距离ai中,问最大的ai是多少。 在所有可能的最小值中,找最大的那个,就是“最小值最大化”。

二分思路:不找搬走石头的各种组合,而是给出一个距离d,检查能不能搬走m块石头而得到最短距离d。把所有的d都试一遍,肯定能找到一个最短的d。用二分法找这个d。

import os
import sys

L, N, M = map(int, input().split())
stone = []    # 石头i和到起起点的距离
for i in range(N):
    t = int(input())
    stone.append(t)

# 思路是能不能搬走某m个石头,得到距离d
def check(d):
    num = 0
    pos = 0     # pos=0 意味着第一次
    # 从头到尾搬石头 如果
    for i in range(0,N):  # 右是开区间,所以我从0到n-1作为石头下标 
        if (stone[i]-pos < d):  # 第i块可以搬走
            num += 1            # 
        else:
            pos = stone[i]
    if num <= M: return True
    else: return False


l, r = 1, L
while (l<r):
    mid = l+(r-l)//2
    if check(mid):
        l = mid+1
    else:
        r = mid-1
    # 现在l可能符合 也可能大1 所以如果l不符合,l-=1 符合就直接输出
if check(l):
    print(l)
else:
    print(l-1)

题目:一元三次方程

题目描述

有形如:ax^3+bx^2+cx+d=0 这样的一个一元三次方程。给出该方程中各项的系数(a,b,c,d 均为实数),并约定该方程存在三个不同实根(根的范围在 −100 至 100 之间),且根与根之差的绝对值 ≥1。要求由小到大依次在同一行输出这三个实根(根与根之间留有空格),并精确到小数点后 2 位。

提示:记方程f(x)=0,若存在 2 个数 x1​ 和 x2​,且x1​<x2​,f(x1​)×f(x2​)<0,则在 (x1​,x2​)之间一定有一个根。

输入描述

输入一行,4 个实数a,b,c,d。

输出描述

输出一行,3 个实根,从小到大输出,并精确到小数点后 2 位。

输入输出样例

示例 1

输入

1 -5 -4 20

输出

-2.00 2.00 5.00

 题解:

def y(x):  #复制函数
   return a*x*x*x+b*x*x+c*x+d
a,b,c,d = map(float,input().split())
for i in range(-100,100):
   left = i  #left 和 right相当于x1和x2
   right = i+1
   y1 = y(left)
   y2 = y(right)
   if y1 == 0:  #令f(x)=0
      print("{:.2f}".format(left),end=' ')
   if y1*y2<0:   #f(x1)*f(x2)<0
      while right-left>=0.001:
         mid = (left+right)/2
         if y(mid)*y(right)<=0:
            left = mid
         else:
            right = mid
      print("{:.2f}".format(right),end=' ')

题目:分巧克力

题目描述

儿童节那天有 K 位小朋友到小明家做客。小明拿出了珍藏的巧克力招待小朋友们。

小明一共有 N 块巧克力,其中第 i 块是 Hi​×Wi 的方格组成的长方形。为了公平起见,

小明需要从这 N 块巧克力中切出 K 块巧克力分给小朋友们。切出的巧克力需要满足:

  1. 形状是正方形,边长是整数;

  2. 大小相同;

例如一块 6x5 的巧克力可以切出 6 块 2x2 的巧克力或者 2 块 3x3 的巧克力。

当然小朋友们都希望得到的巧克力尽可能大,你能帮小明计算出最大的边长是多少么?

输入描述

第一行包含两个整数N,K (1≤N,K≤10^5)。

以下 N 行每行包含两个整数 Hi​,Wi​ (1≤Hi​,Wi​≤10^5)。

输入保证每位小朋友至少能获得一块 1x1 的巧克力。

输出描述

输出切出的正方形巧克力最大可能的边长。

输入输出样例

示例

输入

2 10
6 5
5 6

输出

2

 题解:

1.设立一个检查函数,检查每块巧克力在规定大小情况下取得的最多数量

公式:最多数量=(巧克力长度 // 需要长度)* (巧克力宽度 // 需要长度)

拿这个最多数量与小朋友人数k进行比较

2.利用二分查找找到能满足每个小朋友都能分到巧克力的最大长度

n, k = map(int, input().split())
chocolate = [list(map(int,input().split())) for _ in range(n)]
front, tail = 1, 100000
def find(edge_len):
   global k
   ans = 0
   for wid, len in chocolate:
      ans += (wid//edge_len)*(len//edge_len)
      if ans>=k:
         return True
   return False
while front<=tail:
   mid = (front + tail)//2
   if not find(mid):
      tail = mid - 1
   else:
      front = mid + 1
print(tail)

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值