Python-算法编程100例-二分法(入门级)

 

生活中的二分场景

有一天阿东到图书馆借了 N 本书,出图书馆的时候,警报响了,于是保安把阿东拦下,要检查一下哪本书没有登记出借。阿东正准备把每一本书在报警器下过一下,以找出引发警报的书,但是保安露出不屑的眼神:你连二分查找都不会吗?

于是保安把书分成两堆,让第一堆过一下报警器,报警器响,这说明引起报警的书包含在里面;于是再把这堆书分成两堆,把第一堆过一下报警器,报警器又响,继续分成两堆……

最终,检测了 logN 次之后,保安成功的找到了那本引起警报的书,露出了得意和嘲讽的笑容。于是阿东背着剩下的书走了。

从此,图书馆丢了 N - 1 本书

寻找左侧边界的二分查找

题目1: 业务负载分配

现有一个服务器集群(服务器数量为 serverNum),和一批不同类型的任务(用数组 tasks 表示,下标表示任务类型,值为任务数量)。
现需要把这批任务都分配到集群的服务器上,分配规则如下:
   应业务安全要求,不同类型的任务不能分配到同一台服务器上
   一种类型的多个任务可以分配在多台服务器上
「负载」定义为某台服务器所分配的任务个数,无任务的服务器负载为0。
「最高负载」定义为所有服务器中负载的最大值。
请你制定分配方案,使得分配后「最高负载」的值最小,并返回该最小值。

知识点:

# 算数运算向上取整   math.ceil()

# 算数运算向下取整 math.floor()

解答:

from typing import List
import math
class Solution:
    def get_need_server(self, tasks, load):
        need_server_num = 0
        for task in tasks:
            need_server_num += math.ceil(task / load)
        return need_server_num

    def get_min_load(self, server_num: int, tasks: List[int]) -> int:
        left = 1
        right = max(tasks)
        while left <= right:
            mid = (left + right) // 2
            need_server_num = self.get_need_server(tasks, mid)
            # 负载太小,服务器不够用
            if need_server_num > server_num:
                left = mid + 1
            # 负载太大,服务器没有用完
            elif need_server_num < server_num:
                right = mid - 1
            # 由于要负载最小,因此要继续向左搜索
            elif need_server_num = server_num:
                right = mid - 1

        return left

解析:

a.  为什么while循环条件中是<=而不是<?

初始条件right = max(tasks)可以取到,即搜索区间是左闭右闭区间[left, right]。循环终止条件是left = right + 1, 即[right + 1, right]这时搜索区间为空,可以正常终止。也不会漏掉搜索元素。

b. 为什么是left = mid + 1, right = mid - 1?

本题中搜索区间是左闭右闭[left, right], 当mid搜索过时我们下一步应该搜索[left, mid - 1]或者[mid + 1, right]

c. 为什么最后return left而不是right?

因为终止条件是left = right + 1, 因此写成right + 1也可以。

题目2:在排序数组中查找元素的第一个位置和最后一个位置

https://leetcode.cn/problems/find-first-and-last-position-of-element-in-sorted-array/description/
给你一个按照非递减顺序排列的整数数组 nums,和一个目标值 target。请你找出给定目标值在数组中的开始位置和结束位置。
如果数组中不存在目标值 target,返回 [-1, -1]。
你必须设计并实现时间复杂度为 O(log n) 的算法解决此问题。

解答:

from typing import List
class Solution:
    def searchRange(self, nums: List[int], target: int) -> List[int]:
        if target not in nums:
            return [-1, -1]
        s = len(nums)
        left = 0
        right = s - 1
        # 闭区间[left, right]
        while left <= right:
            mid = (left + right) // 2
            if nums[mid] > target:
                right = mid - 1
            elif nums[mid] < target:
                left = mid + 1
            elif nums[mid] == target:
                right = mid - 1

        for i in range(left, s):
            if nums[i] == target:
                right = i

        return [left, right]

左边界和右边界二分模版的区别:

  • 6
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
以下是Dev-C++实现顺序查找算法二分法查找算法的示例代码: ```c++ #include <iostream> #include <vector> #include <algorithm> using namespace std; // 顺序查找算法 int seqSearch(vector<int>& nums, int target) { for (int i = 0; i < nums.size(); i++) { if (nums[i] == target) { return i; } } return -1; // 查找失败 } // 二分法查找算法 int binarySearch(vector<int>& nums, int target) { int left = 0, right = nums.size() - 1; while (left <= right) { int mid = (left + right) / 2; if (nums[mid] == target) { return mid; } else if (nums[mid] < target) { left = mid + 1; } else { right = mid - 1; } } return -1; // 查找失败 } int main() { vector<int> nums = {3, 5, 2, 8, 4, 7, 1, 6}; sort(nums.begin(), nums.end()); // 二分法查找算法需要有序表 int target = 4; int index1 = seqSearch(nums, target); // 调用顺序查找算法 int index2 = binarySearch(nums, target); // 调用二分法查找算法 if (index1 != -1) { cout << "顺序查找成功,目标元素下标为:" << index1 << endl; } else { cout << "顺序查找失败,未找到目标元素" << endl; } if (index2 != -1) { cout << "二分法查找成功,目标元素下标为:" << index2 << endl; } else { cout << "二分法查找失败,未找到目标元素" << endl; } return 0; } ``` 以上代码中,我们使用了STL中的vector容器来存储顺序表元素,并使用sort函数对其进行排序,以便二分法查找算法能够正确执行。在main函数中,我们分别调用了顺序查找算法二分法查找算法,查找目标元素的值为4。最后,根据返回的下标值,输出查找结果。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值