算法训练营——day1数组二分查找

news2024/11/15 8:04:49

数组是存放在连续空间上的相同数据类型的集合。

注意:下标从0开始;内存空间连续。

正因为数组的内存地址空间连续,所以在删除、添加元素的时候需要移动其他元素。

数组的元素不能删除,只能覆盖!

二维数组特殊

在C++中,二位数组在内存中也是连续的,相当于多个一维数组。

void test_arr() {
    int array[2][3] = {
		{0, 1, 2},
		{3, 4, 5}
    };
    cout << &array[0][0] << " " << &array[0][1] << " " << &array[0][2] << endl;
    cout << &array[1][0] << " " << &array[1][1] << " " << &array[1][2] << endl;
}

int main() {
    test_arr();
}

Result:
0x7ffee4065820 0x7ffee4065824 0x7ffee4065828
0x7ffee406582c 0x7ffee4065830 0x7ffee4065834
由于是int类型,所有每个之间差4字节

而在Java中,由于是由JVM处理,所以毫无规则可言。

public static void test_arr() {
    int[][] arr = {{1, 2, 3}, {3, 4, 5}, {6, 7, 8}, {9,9,9}};
    System.out.println(arr[0]);
    System.out.println(arr[1]);
    System.out.println(arr[2]);
    System.out.println(arr[3]);
}
Result:
[I@7852e922
[I@4e25154f
[I@70dea4e
[I@5c647e05

练习题

1. 二分查找-力扣704(简单)

1.1 题目704. 二分查找

1.2 全闭区间写法

我们定义 target 是在一个在左闭右闭的区间里,也就是[left, right] 

因为定义target在[left, right]区间,所以有如下两点:

  • while (left <= right) 要使用 <= ,因为left == right是有意义的,所以使用 <=
  • if (nums[middle] > target) right 要赋值为 middle - 1,因为当前这个nums[middle]一定不是target,那么接下来要查找的左区间结束下标位置就是 middle - 1
  • 时间复杂度:O(log n)
  • 空间复杂度:O(1)
//Java代码:
class Solution {
    public int search(int[] nums, int target) {
// 避免当 target 小于nums[0] nums[nums.length - 1]时多次循环运算
        if(target<nums[0]||target>nums[nums.length-1]){
            return -1;
        }

        int left=0;
        int right=nums.length-1;
        while(left<=right){
            int mid = left+(right-left)/2;
            if(nums[mid]>target){
                right=mid-1;
            }else if(nums[mid]<target){
                left=mid+1;
            }else{
                return mid;
            }

        }
        return -1;
    }
}

1.3 左闭右开

如果说定义 target 是在一个在左闭右开的区间里,也就是[left, right) 

有如下两点:

  • while (left < right),这里使用 < ,因为left == right在区间[left, right)是没有意义的
  • if (nums[middle] > target) right 更新为 middle,因为当前nums[middle]不等于target,去左区间继续寻找,而寻找区间是左闭右开区间,所以right更新为middle,即:下一个查询区间不会去比较nums[middle]
//左闭右开
class Solution {
    public int search(int[] nums, int target) {
        int left=0;
        int right=nums.length;
        while(left<right){
            int mid = left+(right-left)/2;
            if(nums[mid]>target){
                right=mid;
            }else if(nums[mid]<target){
                left=mid+1;
            }else{
                return mid;
            }

        }
        return -1;
    }
}

2 搜索位置-力扣35(简单)

2.1 题目35:搜索插入位置

2.2 二分解法(Java)

class Solution {
    public int searchInsert(int[] nums, int target) {
        //二分法
        int left = 0;
        int right = nums.length-1;
        while(left<=right){
            int mid = left+(right-left)/2;
            if(target==nums[mid]){
                return mid;
            }else if(target<nums[mid]){
                right=mid-1;
            }else if(target>nums[mid]){
                left=mid+1;
            }
        }
        return right+1;

    }
}

2.3 C解法

class Solution {
    // lower_bound 返回最小的满足 nums[i] >= target 的 i
    // 如果数组为空,或者所有数都 < target,则返回 nums.size()
    // 要求 nums 是非递减的,即 nums[i] <= nums[i + 1]

    // 闭区间写法
    int lower_bound(vector<int>& nums, int target) {
        int left = 0, right = (int) nums.size() - 1; // 闭区间 [left, right]
        while (left <= right) { // 区间不为空
            // 循环不变量:
            // nums[left-1] < target
            // nums[right+1] >= target
            int mid = left + (right - left) / 2;
            if (nums[mid] < target) {
                left = mid + 1; // 范围缩小到 [mid+1, right]
            } else {
                right = mid - 1; // 范围缩小到 [left, mid-1]
            }
        }
        return left;
    }

    // 左闭右开区间写法
    int lower_bound2(vector<int>& nums, int target) {
        int left = 0, right = nums.size(); // 左闭右开区间 [left, right)
        while (left < right) { // 区间不为空
            // 循环不变量:
            // nums[left-1] < target
            // nums[right] >= target
            int mid = left + (right - left) / 2;
            if (nums[mid] < target) {
                left = mid + 1; // 范围缩小到 [mid+1, right)
            } else {
                right = mid; // 范围缩小到 [left, mid)
            }
        }
        return left;
    }

    // 开区间写法
    int lower_bound3(vector<int>& nums, int target) {
        int left = -1, right = nums.size(); // 开区间 (left, right)
        while (left + 1 < right) { // 区间不为空
            // 循环不变量:
            // nums[left] < target
            // nums[right] >= target
            int mid = left + (right - left) / 2;
            if (nums[mid] < target) {
                left = mid; // 范围缩小到 (mid, right)
            } else {
                right = mid; // 范围缩小到 (left, mid)
            }
        }
        return right;
    }

public:
    int searchInsert(vector<int>& nums, int target) {
        return lower_bound(nums, target); // 选择其中一种写法即可
    }
};

3 查找元素第一位和最后一位的下标-力扣34(中等)

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

3.2 解法JAVA

寻找target在数组里的左右边界,有如下三种情况:

  • 情况一:target 在数组范围的右边或者左边,例如数组{3, 4, 5},target为2或者数组{3, 4, 5},target为6,此时应该返回{-1, -1}
  • 情况二:target 在数组范围中,且数组中不存在target,例如数组{3,6,7},target为5,此时应该返回{-1, -1}
  • 情况三:target 在数组范围中,且数组中存在target,例如数组{3,6,7},target为6,此时应该返回{1, 1}
//JAVA版本
class Solution {
    int[] searchRange(int[] nums, int target) {
        int leftBorder = getLeftBorder(nums, target);
        int rightBorder = getRightBorder(nums, target);
        // 情况一:不在数组范围内
        if (leftBorder == -2 || rightBorder == -2) return new int[]{-1, -1};
        // 情况三:找到了这个数字
        if (rightBorder - leftBorder > 1) return new int[]{leftBorder + 1, rightBorder - 1};
        // 情况二:在数组范围内但是没有这个数字
        return new int[]{-1, -1};
    }

    int getRightBorder(int[] nums, int target) {
        int left = 0;
        int right = nums.length - 1;
        int rightBorder = -2; // 记录一下rightBorder没有被赋值的情况
        while (left <= right) {
            int middle = left + ((right - left) / 2);
            if (nums[middle] > target) {
                right = middle - 1;
            } else { // 寻找右边界,nums[middle] == target的时候更新left
                left = middle + 1;
                rightBorder = left;
            }
        }
        return rightBorder;
    }

    int getLeftBorder(int[] nums, int target) {
        int left = 0;
        int right = nums.length - 1;
        int leftBorder = -2; // 记录一下leftBorder没有被赋值的情况
        while (left <= right) {
            int middle = left + ((right - left) / 2);
            if (nums[middle] >= target) { // 寻找左边界,nums[middle] == target的时候更新right
                right = middle - 1;
                leftBorder = right;
            } else {
                left = middle + 1;
            }
        }
        return leftBorder;
    }
}

3.2 解法C

//C嘎嘎版本
class Solution {
public:
    vector<int> searchRange(vector<int>& nums, int target) {
        int leftBorder = getLeftBorder(nums, target);
        int rightBorder = getRightBorder(nums, target);
        // 情况一
        if (leftBorder == -2 || rightBorder == -2) return {-1, -1};
        // 情况三
        if (rightBorder - leftBorder > 1) return {leftBorder + 1, rightBorder - 1};
        // 情况二
        return {-1, -1};
    }
private:
     int getRightBorder(vector<int>& nums, int target) {
        int left = 0;
        int right = nums.size() - 1;
        int rightBorder = -2; // 记录一下rightBorder没有被赋值的情况
        while (left <= right) {
            int middle = left + ((right - left) / 2);
            if (nums[middle] > target) {
                right = middle - 1;
            } else { // 寻找右边界,nums[middle] == target的时候更新left
                left = middle + 1;
                rightBorder = left;
            }
        }
        return rightBorder;
    }
    int getLeftBorder(vector<int>& nums, int target) {
        int left = 0;
        int right = nums.size() - 1;
        int leftBorder = -2; // 记录一下leftBorder没有被赋值的情况
        while (left <= right) {
            int middle = left + ((right - left) / 2);
            if (nums[middle] >= target) { // 寻找左边界,nums[middle] == target的时候更新right
                right = middle - 1;
                leftBorder = right;
            } else {
                left = middle + 1;
            }
        }
        return leftBorder;
    }
};

4 平方根-力扣69(简单)

4.1 题目:x 的平方根 

4.2 二分法求解

class Solution {
    public int mySqrt(int x) {
        int left=0;
        int ret=-1;
        int right=x;
        while(left<=right){
            int mid = left+(right-left)/2;
            if((long)mid*mid<=x){
                ret = mid;
                left=mid+1;
            }else{
                right=mid-1;
            }
        }
        return ret;

    }
}

5 有效完全平方数-力扣367(简单)

5.1 题目:367. 有效的完全平方数

5.2 暴力与二分

//暴力解法
class Solution {
    public boolean isPerfectSquare(int num) {
        long x=1;
        long sq=1;
        while(sq<=num){
            if(sq==num){
                return true;
            }
            x++;
            sq=x*x;
        }
        return false;
    }
}
class Solution {
    public boolean isPerfectSquare(int num) {
        //二分
        int left=0;
        int right=num;
        while(left<=right){
            int mid = left+(right-left)/2;
            long sq = (long) mid*mid;
            if(sq<num){
                left=mid+1;
            }else if(sq>num){
                right=mid-1;
            }else {
                return true;
            }
        }
        return false;
    }
}

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

多目标应用:基于NSGA3的移动机器人路径规划研究(提供MATLAB代码)

一、机器人路径规划介绍 移动机器人&#xff08;Mobile robot&#xff0c;MR&#xff09;的路径规划是 移动机器人研究的重要分支之&#xff0c;是对其进行控制的基础。根据环境信息的已知程度不同&#xff0c;路径规划分为基于环境信息已知的全局路径规划和基于环境信息未知或…

Python函数(11自定义模块第三方模块内置模块)

Python基础语法文章导航&#xff1a; Python基础&#xff08;01初识数据类型&变量&#xff09;Python基础&#xff08;02条件&循环语句&#xff09;Python基础&#xff08;03字符串格式化&运算符&进制&编码&#xff09;Python基础&#xff08;04 基础练习…

定时器方案:时间表盘

目录 一&#xff1a;前言 二&#xff1a;手搓时间表盘 1、任务结点&#xff0c;层级&#xff0c;表盘的结构体 2、表盘的初始化 3、添加定时任务 4、删除定时任务 5、检查任务是否超时 6、清空任务 一&#xff1a;前言 我之前有两篇文章是写定时器方案的&#xff0c;大家…

智菜谱推|基于SprinBoot+vue的智能菜谱推荐系统(源码+数据库+文档)

智能菜谱推荐系统 基于SprinBootvue的智能菜谱推荐系统 一、前言 二、系统设计 三、系统功能设计 系统功能实现 管理员功能模块实现 四、数据库设计 五、核心代码 六、论文参考 七、最新计算机毕设选题推荐 八、源码获取&#xff1a; 博主介绍&#xff1a;✌️大厂…

【开源免费】基于SpringBoot+Vue.JS渔具租赁系统(JAVA毕业设计)

本文项目编号 T 005 &#xff0c;文末自助获取源码 \color{red}{T005&#xff0c;文末自助获取源码} T005&#xff0c;文末自助获取源码 目录 一、系统介绍二、演示录屏三、启动教程四、功能截图五、文案资料5.1 选题背景5.2 国内外研究现状5.3 可行性分析 六、核心代码6.1 渔…

低空经济概念火爆:无人机飞手人才培养先行

随着科技的飞速发展&#xff0c;低空经济作为新兴的经济形态&#xff0c;正以前所未有的速度崛起&#xff0c;成为推动产业升级和经济发展的新引擎。无人机作为低空经济的重要组成部分&#xff0c;其应用领域已从最初的军事侦察、航拍扩展到农业植保、物流配送、环境监测、应急…

使用corrplot绘制行、列不同,且带有p值显著性标注的相关系数图

导读&#xff1a; 相关系数衡量两个变量之间的线性关系&#xff0c;通常以N*N的矩阵形式展示。例如样品vs样品&#xff0c;或者基因vs基因的相关性。本文介绍了使用corrplot R包绘制M*N的相关系数矩阵&#xff0c;例如M个基因表达与N个代谢物信号间的相关性&#xff0c;同时带…

国产芯片+国产操作系统打造办公系统

在《使用国产操作系统作为开发系统》一文中&#xff0c;我介绍了将开发系统从 Ubuntu 替换为 Deepin 系统的过程。经过一个多月的使用&#xff0c;Deepin 系统已然成为我的主力开发平台&#xff0c;其顺手程度让我对国产操作系统的信心大增。于是&#xff0c;我开始将目光瞄向公…

顶级开源许可证详解

目录 软件许可证类型&#xff1a;版权左派和宽容型 顶级开源许可证详解 GNU 通用公共许可证 (GPL) Apache 许可证 Microsoft 公共许可证 (Ms-PL) 伯克利软件发行版 (BSD) 通用开发和分发许可证 (CDDL) Eclipse 公共许可证 (EPL) MIT 许可证 了解你的开源许可证&#…

java编辑器——IntelliJ IDEA

java编辑器有两种选择——IntelliJ IDEA和VsCode。其中IntelliJ IDEA现在是企业用的比较多的&#xff0c;是专门为java设计的&#xff0c;而VsCode则是通过插件来实现Java编辑的。 1.IntelliJ IDEA 官网下载链接&#xff1a;https://www.jetbrains.com/idea/ 注意选择社区版…

AWS-亚马逊网络服务(基础服务)-AWS 定价计算器-概述与动手部署:

让我们来概述并亲身实践如何使用 AWS 定价计算器来计算 概述&#xff1a; AWS 定价计算器是 Amazon Web Services (AWS) 提供的基于 Web 的工具&#xff0c;可帮助用户估算其特定用例的 AWS 服务成本。欢迎来到雲闪世界。 它允许客户建模他们的基础设施并根据他们打算使用的…

【AI 绘画】更快?更省显存?支持 FLUX?使用绘世启动器安装 SD WebUI Forge

使用绘世启动器安装 SD WebUI Forge 下载绘世启动器 绘世启动器下载地址1&#xff1a;https://gitee.com/licyk/term-sd/releases/download/archive/hanamizuki.exe 绘世启动器下载地址2&#xff1a;https://www.bilibili.com/video/BV1ne4y1V7QU 新建一个文件夹取名sd-webui-…

中仕公考怎么样?公务员考试什么时候补录?

公务员考试补录的时间和方法通常因地区和职位的不同有所区别&#xff0c;一般来说&#xff0c;这一过程会在面试、体检和考核环节完成后启动。 如果在招录过程中出现职位空缺或者并未全部招满的情况&#xff0c;就会进行补录。用人单位会通过其官方或公告形式公布相关信息&…

指针5.回调函数与qsort

今天来学习回调函数与qsort 目录 1.回调函数实现模拟计算器代码的简化原代码运行结果简化代码运行结果 qsort函数排序整型数据代码运行结果 qsort排序结构数据代码 qsort函数的模拟实现代码运行结果 总结 1.回调函数 回调函数就是⼀个通过函数指针调用的函数。 如果你把函数的…

JavaEE第22节 TCP段(报文)结构剖析

目录&#xff08;关于字段有不理解的&#xff0c;哪里不会点哪里&#x1f618;&#xff09; 逻辑结构字段解析一、源端口&目的端口二、序号&确认序号三、头部长度四、保留位五、特殊标志位六、窗口大小七、校验和八、紧急指针九、可选选项十、数据 逻辑结构 如图&…

入门Java编程的知识点—>Http协议(day20)

了解http协议是什么掌握http请求信息、响应信息格式 项目目标&#xff1a; 实现本地客户端与服务器一问一答的请求与响应,了解http协议即可. 项目步骤&#xff1a; 服务器端代码编写 先在当前src文件下新建一个包: webserver,再该包下创建一个类Server&#xff0c;书写代码如…

带着耐心细心平常心和编程共舞

编程是什么&#xff1f;一个工具、一门技术还是一个爱好&#xff0c;不同的对待方法会带来不同的心态、产生不同的结果。编程需要扎实的基础、严密的思维和开阔的视角&#xff0c;新技术和框架日新月异&#xff0c;只有抱着科学、乐在其中的态度才能掌握高效的学习、实践方法。…

Matrix:重塑APM领域,以简驭繁的性能监控新纪元

在数字化转型的浪潮中&#xff0c;应用程序的性能监控&#xff08;APM&#xff09;已成为企业IT架构中不可或缺的一环。随着业务复杂度的提升和用户对体验要求的日益增高&#xff0c;如何高效、精准地监控并优化应用性能&#xff0c;成为了每个开发者和技术团队面临的重大挑战。…

机器学习(五) -- 监督学习(8) --神经网络1

系列文章目录及链接 上篇&#xff1a;机器学习&#xff08;五&#xff09; -- 无监督学习&#xff08;2&#xff09; --降维2 下篇&#xff1a; 前言 tips&#xff1a;标题前有“***”的内容为补充内容&#xff0c;是给好奇心重的宝宝看的&#xff0c;可自行跳过。文章内容被…

2.3导数与微分的基础与应用

1. 导数的基本概念 大家好&#xff0c;欢迎来到我们的数学大讲堂&#xff01;今天我们要聊聊一个有点酷又有点恐怖的东西——导数。别担心&#xff0c;不是让你在黑板上画曲线的那种&#xff0c;而是关于“变化率”的一种数学表达。 那么&#xff0c;什么是导数呢&#xff1f…