算法设计与分析实验一:二分查找

目录

一、有序数组中的单一元素   

1.1思路

1.2 代码实现

1.3 运行结果

二、长度最小的子数组

2.1思路

2.2 代码

2.3 运行结果

三、 山脉数组中查找目标值

3.1 思路

3.2 代码

3.3 运行结果

四、寻找旋转排序数组中的最小值

4.1思路

4.2代码

4.3 运行结果


一、有序数组中的单一元素   

力扣第540题

1.1思路

利用二分查找思想:

根据要求在 O(log n) 的时间复杂度和 O(1) 空间复杂度内找出只出现一次的数,因此可以考虑使用二分查找结合异或运算的方法。

而且由于数组中每个元素都会出现两次,唯有一个数只会出现一次,因此在此题中可以使用异或运算。异或运算具有以下性质:

①任何数和 0 进行异或运算,结果仍然是这个数本身。

②任何数和其自身进行异或运算,结果为 0。

基于这个性质,我们可以利用异或运算来找出只出现一次的那个数。

具体步骤如下:

1.初始化左指针 left = 0 和右指针 right = n-1,其中 n 是数组长度。

2.进入循环,直到 left > right:

·计算中间位置 mid = (left + right) // 2。

·如果 mid 是偶数,判断 nums[mid] 是否等于 nums[mid+1]。如果相等,则说明目标元素在 mid 右边,将 left 指针移到 mid+2;否则,目标元素在 mid 左边,将 right 指针移到 mid。

·如果 mid 是奇数,判断 nums[mid] 是否等于 nums[mid-1]。如果相等,则说明目标元素在 mid 右边,将 left 指针移到 mid+1;否则,目标元素在 mid 左边,将 right 指针移到 mid-1。

3.循环结束后,返回 nums[left]。

这样就可以在 O(log n) 的时间复杂度和 O(1) 空间复杂度内找出只出现一次的数。

1.2 代码实现

def singleNonDuplicate(nums):
    left, right = 0, len(nums) - 1
    while left < right:
        mid = (left + right) // 2
        if mid % 2 == 0:
            if nums[mid] == nums[mid+1]:
                left = mid + 2
            else:
                right = mid
        else:
            if nums[mid] == nums[mid-1]:
                left = mid + 1
            else:
                right = mid - 1
    return nums[left]

# 示例测试
print(singleNonDuplicate([1,1,2,2,3,4,4,8,8]))  
print(singleNonDuplicate([3,3,7,7,10,10,11]))  

1.3 运行结果

代码中的测试的数组:

[1,1,2,2,3,4,4,8,8]  元素3出现一次

[3,3,7,7,10,10,11]  元素11出现一次

二、长度最小的子数组

力扣第209题

2.1思路

为了找到满足总和大于等于 target 的长度最小的连续子数组。

思路:滑动窗口前缀和、二分查找

具体思路如下:

首先初始化左指针 left、右指针 right 和当前窗口内元素的和 window_sum,初始值均为 0。

进入循环,当右指针小于数组长度时执行以下操作:

将右指针 right 对应元素的值加到 window_sum 中。

如果 window_sum 大于等于目标值 target,进入内部循环:

更新最小长度 min_len,为当前窗口长度与之前的最小长度的较小值。

从当前窗口中减去左指针 left 对应元素的值,并将左指针向右移动一位。

将右指针向右移动一位。

返回最小长度 min_len。

如果不存在满足条件的子数组,则返回0。

2.2 代码

from typing import List

class Solution:
    def findMin(self, nums: List[int]) -> int:
        left, right = 0, len(nums) - 1

        while left < right:
            mid = (left + right) // 2

            if nums[mid] > nums[right]:
                left = mid + 1
            elif nums[mid] < nums[right]:
                right = mid
            else:
                right -= 1

        return nums[left]


if __name__ == "__main__":
    solution = Solution()

    # 测试示例1
    nums_1 = [4, 5, 6, 7, 0, 1, 2]
    result_1 = solution.findMin(nums_1)
    print(f"The minimum element in {nums_1} is: {result_1}")

    # 测试示例2
    nums_2 = [3, 4, 5, 1, 2]
    result_2 = solution.findMin(nums_2)
    print(f"The minimum element in {nums_2} is: {result_2}")

    # 测试示例3
    nums_3 = [1]
    result_3 = solution.findMin(nums_3)
    print(f"The minimum element in {nums_3} is: {result_3}")

2.3 运行结果

由于在[1,1,1,1,1,1,1,1]中无法得到和为11的连续子数组,返回0

由于篇幅限制,下面两题仅展示运行结果

三、 山脉数组中查找目标值

力扣第1095题

3.1 思路

当给定一个山脉数组 mountainArr 和目标值 target,我们需要找到能使得 mountainArr.get(index) 等于 target 的最小下标 index。

解题思路如下:

首先,我们需要确定山峰的位置。山峰是指数组中的一个最大值,满足 A[i-1] < A[i] > A[i+1] 的条件。我们可以使用二分查找来找到山峰的位置。

定义左指针 left 为数组的起始位置,右指针 right 为数组的结束位置。

进入循环,当 left < right 时进行迭代:

计算中间位置 mid,即 (left + right) // 2。

如果 mountainArr.get(mid) < mountainArr.get(mid+1),则说明 mid 左侧为上升趋势,右侧可能存在山峰,将 left 移至 mid + 1。

否则,mid 右侧为下降趋势,左侧可能存在山峰,将 right 移至 mid。

循环结束后,left 或 right 即为山峰所在位置,记为 peak。

接下来,我们可以对山峰的左右两侧分别进行二分查找:

使用标准的二分查找方法在 [0, peak] 区间内查找目标值 target。如果找到目标值,直接返回其下标。

如果左侧未找到目标值,则在 [peak+1, n-1] 区间内进行反向二分查找。即令 mountainArr.get(mid) > target 时移动右指针,反之移动左指针。

如果右侧未找到目标值或左侧未找到目标值,则返回 -1。

综上所述,我们可以定义一个辅助函数 binary_search 来实现二分查找。

在编写示例测试部分时,首先进行 MountainArray 类的设计并在其中实现 length() 和 get(index) 方法。这两个方法分别用于获取数组长度和获取指定下标的元素。

3.2 代码

class Solution:
    def findInMountainArray(self, target: int, mountainArr: 'MountainArray') -> int:
        n = mountainArr.length()
        left, right = 0, n - 1

        # 二分查找山峰所在的位置
        while left < right:
            mid = (left + right) // 2
            if mountainArr.get(mid) < mountainArr.get(mid+1):
                left = mid + 1
            else:
                right = mid

        peak = left   # 左右端点重合处即为山峰位置
        idx = self.binary_search(mountainArr, 0, peak, target)
        if idx != -1:
            return idx
        return self.binary_search(mountainArr, peak+1, n-1, target)

    def binary_search(self, mountainArr, left, right, target):
        while left <= right:
            mid = (left + right) // 2
            cur = mountainArr.get(mid)
            if cur == target:
                return mid
            elif cur < target:
                left = mid + 1
            else:
                right = mid - 1
        return -1


class MountainArray:
    def __init__(self, arr):
        self.arr = arr

    def length(self):
        return len(self.arr)

    def get(self, index):
        return self.arr[index]


# 示例测试
if __name__ == "__main__":
    # 创建山脉数组实例
    mountain_arr_1 = MountainArray([1, 2, 3, 4, 5, 3, 1])
    mountain_arr_2 = MountainArray([0, 1, 2, 4, 2, 1, 0])
    # 创建解决方案实例
    solution = Solution()

    # 测试1查找目标值为 3 的下标
    target_1 = 3
    result_1 = solution.findInMountainArray(target_1, mountain_arr_1)
    print(f"[1, 2, 3, 4, 5, 3, 1]测试一(查找3)结果: {result_1}")
    # 测试2查找目标值为 5 的下标
    target_2 = 5
    result_2 = solution.findInMountainArray(target_2, mountain_arr_2)
    print(f"[0, 1, 2, 4, 2, 1, 0]测试二(查找5)结果: {result_2}")

3.3 运行结果

测试一中,元素3的下标为2,成功找到并输出了其下标。

测试二中,元素5未在数组中出现,按照题目要求返回了-1

四、寻找旋转排序数组中的最小值

力扣第154题

4.1思路

采用二分查找的方法:

首先定义一个 Solution 类,其中包含一个名为 findMin 的方法,用于找到给定数组中的最小元素。

在 findMin 方法中,定义左右指针 left 和 right,初始值分别为 0 和数组长度减 1,表示当前搜索范围为整个数组。

进入循环,当 left 小于 right 时执行以下步骤:

计算中间元素的索引 mid = (left + right) // 2。

比较 nums[mid] 和 nums[right] 的值:

如果 nums[mid] > nums[right],说明最小元素在 mid 的右侧,更新 left = mid + 1。

如果 nums[mid] < nums[right],说明最小元素在 mid 的左侧或者就是 nums[mid],更新 right = mid。

如果 nums[mid] == nums[right],无法判断最小元素在哪一侧,因此将 right 减一,缩小搜索范围。

循环结束后,返回 nums[left](或 nums[right])作为最小元素。

在 main 函数中,创建 Solution 类的实例,然后进行示例测试,验证代码的正确性。

4.2代码

1.from typing import List
2.
3.class Solution:
4.    def findMin(self, nums: List[int]) -> int:
5.        left, right = 0, len(nums) - 1
6.
7.        while left < right:
8.            mid = (left + right) // 2
9.
10.            if nums[mid] > nums[right]:
11.                left = mid + 1
12.            elif nums[mid] < nums[right]:
13.                right = mid
14.            else:
15.                right -= 1
16.
17.        return nums[left]
18.
19.
20.if __name__ == "__main__":
21.    solution = Solution()
22.
23.    # 测试示例1
24.    nums_1 = [4, 5, 6, 7, 0, 1, 2]
25.    result_1 = solution.findMin(nums_1)
26.    print(f"The minimum element in {nums_1} is: {result_1}")
27.
28.    # 测试示例2
29.    nums_2 = [3, 4, 5, 1, 2]
30.    result_2 = solution.findMin(nums_2)
31.    print(f"The minimum element in {nums_2} is: {result_2}")
32.
33.    # 测试示例3
34.    nums_3 = [1]
35.    result_3 = solution.findMin(nums_3)
36.    print(f"The minimum element in {nums_3} is: {result_3}")

4.3 运行结果

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/354033.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

超越 Node.js:Bun 的创新与突破

1. Bun Bun 是一个全新的 JavaScript 运行时&#xff0c;类似于 Node.js 和 Deno&#xff0c;它专注于提供出色的性能和开发者体验。Bun 的一些特点包括&#xff1a; 快速的性能&#xff1a;Bun 旨在提供高性能&#xff0c;无论是启动时间、执行速度还是安装依赖包的速度。 兼…

ORM-02-Hibernate 对象关系映射(ORM)框架

拓展阅读 The jdbc pool for java.(java 手写 jdbc 数据库连接池实现) The simple mybatis.&#xff08;手写简易版 mybatis&#xff09; Hibernate Hibernate ORM 允许开发者更轻松地编写那些数据在应用程序进程结束后仍然存在的应用程序。 作为一个对象关系映射&#xff08…

蓝桥杯省赛无忧 编程14 肖恩的投球游戏加强版

#include <stdio.h> #define MAX_N 1003 int a[MAX_N][MAX_N], d[MAX_N][MAX_N]; // 差分数组的初始化 void init_diff(int n, int m) {for (int i 1; i < n; i) {for (int j 1; j < m; j) {d[i][j] a[i][j] - a[i-1][j] - a[i][j-1] a[i-1][j-1];}} } // 对差…

【王道数据结构】【chapter2线性表】【P44t17~t20】【统考真题】

目录 2009年统考 2012年统考 2015年统考 2019年统考 2009年统考 #include <iostream>typedef struct node{int data;node* next; }node,*list;list Init() {list head(list) malloc(sizeof (node));head->next nullptr;head->data-1;return head; }list Buyne…

QA-GNN: 使用语言模型和知识图谱的推理问答

Abstract 使用预训练语言模型&#xff08;LMs&#xff09;和知识图谱&#xff08;KGs&#xff09;的知识回答问题的问题涉及两个挑战&#xff1a;在给定的问答上下文&#xff08;问题和答案选择&#xff09;中&#xff0c;方法需要&#xff08;i&#xff09;从大型知识图谱中识…

C++:auto 关键字 范围for

目录 auto 关键字&#xff1a; 起源&#xff1a; auto的使用细则&#xff1a; auto不能推导的场景&#xff1a; 范围for&#xff1a; 范围for的使用条件&#xff1a; C的空指针&#xff1a; 注意&#xff1a; auto 关键字&#xff1a; 起源&#xff1a; 随着程序越…

蜡烛图采用PictureBox控件绘制是实现量化的第一步

股票软件中的蜡烛图是非常重要的一个东西&#xff0c;这里用VB6.0自带的Picture1控件的Line方法就可以实现绘制。 关于PictureBox 中的line 用法 msdn 上的说明为如下所示 object.Line [Step] (x1, y1) [Step] - (x2, y2), [color], [B][F] 然…

【Axure教程0基础入门】02高保真基础

02高保真基础 1.高保真原型的要素 &#xff08;1&#xff09;静态高保真原型图 尺寸&#xff1a;严格按照截图比例&#xff0c;参考线 色彩&#xff1a;使用吸取颜色&#xff0c;注意渐变色 贴图&#xff1a;矢量图/位图&#xff0c;截取&#xff0c;覆盖等 &#xff08;…

【Java Kubernates】Java调用kubernates提交Yaml到SparkOperator

背景 目前查询框架使用的是trino&#xff0c;但是trino也有其局限性&#xff0c;需要准备一个备用的查询框架。考虑使用spark&#xff0c;spark operator也已经部署到k8s&#xff0c;现在需要定向提交spark sql到k8s的sparkoperator上&#xff0c;使用k8s资源执行sql。 对比 …

【linux】查看进程和子进程

在Linux系统中&#xff0c;可以使用多个命令来查看进程及其子进程。以下是一些常用的方法&#xff1a; 1. ps 命令 ps 命令用于显示当前进程的状态。可以结合不同的选项来查看进程及其子进程。 查看进程树&#xff1a; ps -auxf - -a 显示所有进程。 - -u 显示进程的用户/所…

2024年最适合开Palworld的游戏服务器

如果要开Palworld服务器&#xff0c;当然要选大内存的服务器 在雨云&#xff0c;你不仅可以 链接&#xff1a;雨云 - 新一代云服务提供商欢迎来到以用户体验为优先的雨云&#xff0c;我们提供稳定高速的国际虚拟主机&#xff0c;云服务器产品&#xff0c;强大的功能&#xff…

MySQL中使用percona-xtrabackup工具 三种备份及恢复 (超详细教程)

CSDN 成就一亿技术人&#xff01; 今天讲讲再MySQL中使用percona-xtrabackup这个开源工具来实现在线备份。 CSDN 成就一亿技术人&#xff01; 目录 介绍percona-xtrabackup 安装Percona 完整备份 备份流程 恢复流程 1.模拟文件损坏 2.滚回日志 3.恢复数据目录 4.授权…

复现五 LMDeploy 的量化和部署

0基础知识 一步一步跟着教程复现第五&#xff1a;LMDeploy 的量化和部署 复现一&#xff1a; 轻松玩转书生浦语大模型internlm-demo 配置验证过程_ssh -cng -l 7860:127.0.0.1:6006 rootssh.intern-ai-CSDN博客文章浏览阅读827次&#xff0c;点赞17次&#xff0c;收藏24次。…

BTC的数据结构Merkle Tree和Hash pointer

比特币是一种基于区块链技术的加密数字货币&#xff0c;其底层数据结构被设计为分布式&#xff0c;去中心化的。它的核心数据结构是一个链式的区块&#xff0c;每个区块都包含了多笔交易记录和一个散列值。 比特币的底层数据结构使用了两个关键概念&#xff1a;hash pointer和…

01 Redis的特性+下载安装启动+Redis自动启动+客户端连接

1.1 NoSQL NoSQL&#xff08;“non-relational”&#xff0c; “Not Only SQL”&#xff09;&#xff0c;泛指非关系型的数据库。 键值存储数据库 &#xff1a; 就像 Map 一样的 key-value 对。如Redis文档数据库 &#xff1a; NoSQL 与关系型数据的结合&#xff0c;最像关系…

AP3464 车充 适配器IC 4-30V 2.4A 同步降压驱动器

AP3464 是一款支持宽电压输入的同步降压电源管理芯片&#xff0c;输入电压 4-30V 范围内可实现2.4A 的连续电流输出。通过调节 FB 端口的分压电阻&#xff0c;设定输出 1.8V 到 28V 的稳定电压。AP3464 具有优秀的恒压/恒流(CC/CV)特性。AP3464 采用电流模式的环路控制原理&…

Spring5深入浅出篇:Spring中ioc(控制反转)与DI(依赖注入)

Spring5深入浅出篇:Spring中ioc(控制反转)与DI(依赖注入) 反转(转移)控制(IOC Inverse of Control) 控制&#xff1a;对于成员变量赋值的控制权 反转控制&#xff1a;把对于成员变量赋值的控制权&#xff0c;从代码中反转(转移)到Spring⼯⼚和配置⽂件中完成好处&#xff1a;…

基于YOLOv8的摄像头吸烟行为检测系统(Python源码+Pyqt6界面+数据集)

&#x1f4a1;&#x1f4a1;&#x1f4a1;本文主要内容:详细介绍了摄像头下吸烟行为检测系统&#xff0c;在介绍算法原理的同时&#xff0c;给出Pytorch的源码、训练数据集以及PyQt6的UI界面。在界面中可以选择各种图片、视频进行检测识别&#xff0c;可进行置信度、Iou阈值设定…

Pandas.Series.mode() 众数 详解 含代码 含测试数据集 随Pandas版本持续更新

关于Pandas版本&#xff1a; 本文基于 pandas2.2.0 编写。 关于本文内容更新&#xff1a; 随着pandas的stable版本更迭&#xff0c;本文持续更新&#xff0c;不断完善补充。 传送门&#xff1a; Pandas API参考目录 传送门&#xff1a; Pandas 版本更新及新特性 传送门&…

LeetCode---122双周赛

题目列表 3010. 将数组分成最小总代价的子数组 I 3011. 判断一个数组是否可以变为有序 3012. 通过操作使数组长度最小 3013. 将数组分成最小总代价的子数组 II 一、将数组分成最小总代价的子数组I 这道题纯纯阅读理解题&#xff0c;关键在于理解题意。注意&#xff1a;第一…