【感悟《剑指offer》典型编程题的极练之路】01数组篇!

news2025/1/20 5:50:56

                                        ​​​​​​​        ​​​​​​​                                个人主页:秋风起,再归来~

                                           ​​​​​​​                    文章所属专栏:《剑指offer》典型编程题的极练之路        ​​​​​​​        ​​​​​​​        ​​​​​​                                     

                                                                        个人格言:悟已往之不谏,知来者犹可追

                                                                     ​​​​​​​                   克心守己,律己则安!

目录

​编辑

一、面试题1:数组中重复的数字(查重)

1.1 题目一:找出数组中重复的数字

1.2 题目二:不修改数组找出重复的数字

二、面试题2:二维数组中的查找

  三. 完结散花


一、面试题1:数组中重复的数字(查重)

1.1 题目一:找出数组中重复的数字

题目描述

在一个长度为n的数组里的所有数字都在0到n-1的范围内。 数组中某些数字是重复的,但不知道有几个数字是重复的。也不知道每个数字重复几次。请找出数组中任意一个重复的数字。 例如,如果输入长度为7的数组[2,3,1,0,2,5,3],那么对应的输出是2或者3。存在不合法的输入的话输出-1

数据范围:0≤n≤10000 

进阶:时间复杂度 O(n) ,空间复杂度O(n) 

示例:

输入:
[2,3,1,0,2,5,3]
返回值:
2
说明:
2或3都是对的 

牛客网上该题目链接(点击进入)

1.1.1排序法

解决这个问题我们首先可以想到一个非常简单的方法就是把数组进行排序,从有序的数组中找出重复的元素是一件很容易的事情,只需要从头到尾扫描排序后的数组就可以了。排序一个长度为n的数组需要O(nlongn)的时间

1.1.2 哈希表

我们还可以用哈希表来解决这个问题。从头到尾按顺序扫描数组的每个数字,每扫描到一个位置的时候,都可以用O(1)的时间来判断哈希表里是否已经包含了该数字。如果哈希表里还没有这个数字,就把他加入哈希表。如果哈希表里已经存在该数字,就找到一个重复的数字。这个算法的时间复杂度是O(n),但它提高效率是以一个大小为O(n)的哈希表为代价的。

1.1.3 下标索引

我们注意到数组中的数字都在0~n-1的范围内。如果数组中没有重复的数字,那么排序后数字i将出现在下标为i的位置由于数组中有重复的数字,有些位置可能存在多个数字,同时有些位置可能没有位置。

现在我们重新排列一下这个数组。从头到尾依次扫描数组中的每一个数组,当扫描到下标为i的数字(m)时如果这个数字等于i(m=i),则我们接着扫描下一个数字如果不是,那我们就把它(m)和下标为m的那个元素先进行比较,如果m与下标为m的元素的大小相等,那这个数(m)就是重复的数字,如果不相等,那我们就将这两个数字进行交换(即把m放到下标为m的位置)。接下来我们就重复这个比较交换的动作,直到我们发现一个重复的数字。

画个图理解一下:

牛客网上解题的代码如下~

/**
 * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
 *
 * 
 * @param numbers int整型一维数组 
 * @param numbersLen int numbers数组长度
 * @return int整型
 */
int duplicate(int* numbers, int numbersLen ) {
    // write code here
    if(numbers==NULL||numbersLen<=0)
    return -1;
    //第一层循环遍历数组元素
    for(int i=0;i<numbersLen;i++)
    {
        //第二层循环将该元素放到和其值相等的下标的位置
        while(numbers[i]!=i)
        {
            if(numbers[i]==numbers[numbers[i]])
            {
                return numbers[i];
            }
            int tmp= numbers[i];
            numbers[i]=numbers[tmp];
            numbers[tmp]=tmp;
        }
    }
    return -1;
}

代码中尽管有两重循环,但每个数字最多只要交换两次就能找到属于他自己的完位置,因此总的时间复杂度为O(n)。另外,所有的操作都是在原数组上完成的,不需要分配额外的内存空间,所以空间复杂度为O(1)。

1.2 题目二:不修改数组找出重复的数字

题目描述:

在一个长度为n+1的数组里的所有数字都在1~n的范围内,所以数组中至少有一个数字是重复的。请找出数组中任意一个重复的数字,但不能修改输入的数组。

例如:如果输入长度为8 的数组{2,3,5,4,3,2,6,7},那么对应输出的是重复的数字是2或3。

1.2.1 创建临时数组

不能修改临时数组,那我们就创建一个临时的大小为n+1的数组,将原数组中数字为m的元素复制放到临时数组下标为m的位置上,在放入之前我们比较一下它们的值是否相等就可以很容易的找到重复的数字了。不过我们创建了一个大小为n+1的数组,所以这种算法的空间复杂度为O(n),时间复杂度也是O(n)。

那我们接下来就尝试避免使用O(n)的空间看能不能解题~

1.2.2 二分查找

我们假设数组中没有重复的数字,那么对于1~n范围内的数字,我们在遍历原数组后,这些数字出现的次数一定为n但如果原数组中有重复的数字并且在1~n内存在原数组中重复的数字,我们在遍历原数组后,这些数字出现的次数一定大于n。

所以,基于以上的分析,我们不妨借鉴二分查找法的思路将将我们要查重的数据一分为二来查找。

下面举一个栗子进行分析啦~

代码实现如下~

int countrange(int*numbers,int numbersLen,int start,int middle)
 {
    int count=0;
    for(int i=0;i<numbersLen;i++)
    {
        if(numbers[i]>=start&&numbers[i]<=middle)
        {
            count++;
        }
    }
    return count;
 }
int duplicate(int* numbers, int numbersLen ) {
    // write code here
    if(numbers==NULL||numbersLen<=0)
    return -1;
    int start=0;
    int end=numbersLen-1;
    while(start<=end)
    {
        int middle=((end-start)>>1)+start;
        //计算局部范围内数字出现的次数
        int count=countrange(numbers,numbersLen,start,middle);
        if(start==end)//找到最后一个数
        {
            if(count>1)
            return start;
            else
            break;
        }
        if(count>(middle-start+1))//前半段有重
        {
            end=middle;
        }
        else //后半段有重
        {
            start=middle+1;
        }
    }
    return -1;
}

需要指出的是上述代码按照二分查找的思路,如果输入长度为n的数组,那么函数countrange将被调用O(logn)次,每次需要O(n)的时间,因此总的时间复杂度为O(nlogn),空间复杂度为O(1)。和前面提到的需要O(n)的辅助空间的算法相比,这种算法相当于以时间换空间

二、面试题2:二维数组中的查找

题目描述:

编写一个高效的算法来搜索 m x n 矩阵 matrix 中的一个目标值 target 。该矩阵具有以下特性:

  • 每行的元素从左到右升序排列。
  • 每列的元素从上到下升序排列。

力扣上的题目链接(点击进入)

在具有上述特性的矩阵中搜索目标值的问题可以使用一种高效的算法来解决,这种算法的时间复杂度为O(m + n)这个算法的基本思想是,从矩阵的右上角或左下角开始搜索,然后利用矩阵的特性来决定下一步的搜索方向。

以下是基于右上角开始搜索的算法步骤:

  1. 初始化一个指针,指向矩阵的右上角元素(即第一行最后一列的元素)。
  2. 比较当前指针指向的元素与目标值的大小:
    • 如果当前元素等于目标值,则搜索成功,返回该元素的位置。
    • 如果当前元素大于目标值,由于矩阵的每一列都是升序排列的,因此目标值不可能在当前列的更下方位置,所以将指
    • 针向左移动一列。
    • 如果当前元素小于目标值,由于矩阵的每一行都是升序排列的,因此目标值不可能在当前行的更左侧位置,所以将指针向下移动一行。
  3. 重复步骤2,直到找到目标值,或者指针移出矩阵的范围(即指针指向的行列号超出矩阵的边界)。如果指针移出矩阵范围仍未找到目标值,则搜索失败,返回相应的结果。

解题的具体代码如下~

bool searchMatrix(int** matrix, int matrixSize, int* matrixColSize, int target){
    if(matrix==NULL||matrixSize<=0)
    return false;
    int row=0;//从第0行
    int col=(*matrixColSize-1);//从最后一列
    while(row<matrixSize&&col>=0)
    {
        if(matrix[row][col]==target)
        return true;
        else if(matrix[row][col]<target)
        row++;
        else
        col--;
    }
    return false;
}

  三. 完结散花

好了,这期的分享到这里就结束了~

如果这篇博客对你有帮助的话,可以用你们的小手指点一个免费的赞并收藏起来哟~

如果期待博主下期内容的话,可以点点关注,避免找不到我了呢~

我们下期不见不散~~

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

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

相关文章

Android Audio相关

AudioManager AudioService的Bp端&#xff0c;调用AudioManager>AudioService&#xff08;代码实现&#xff09; AudioService 继承自IAudioService.Stub&#xff0c;为Bn端 AudioSystem AudioService功能实现都依赖于AudioSystem&#xff0c;AudioService通过AudioSys…

python的FastAPI 快速入门

你好&#xff0c;我是 shengjk1&#xff0c;多年大厂经验&#xff0c;努力构建 通俗易懂的、好玩的编程语言教程。 欢迎关注&#xff01;你会有如下收益&#xff1a; 了解大厂经验拥有和大厂相匹配的技术等 希望看什么&#xff0c;评论或者私信告诉我&#xff01; 文章目录 一…

ESM对比CommonJS

以下内容均总结自es-modules-a-cartoon-deep-dive 1. ESM是异步的而CommonJS是同步的 异步是ESM面临的最大挑战。和CommonJS的执行环境Node获取模块文件的方式不同&#xff0c;ESM获取模块文件是通过网络。如果ESM从获取到执行所有模块都是顺序进行会导致主线程长期处于pendi…

AI预测福彩3D第15弹【2024年3月20日预测--第3套算法重新开始计算第4次测试】

今天咱们继续对第3套算法进行第4次测试&#xff0c;第3套算法加入了012路的权重。废话不多说了&#xff0c;直接上结果吧~ 最终&#xff0c;经过研判分析&#xff0c;2024年3月21日福彩3D的七码预测结果如下&#xff1a; 百位&#xff1a;4 5 7 1 0 6 2 十位&#xff1a;3 1 5 …

第十节HarmonyOS 常用容器组件4-Grid与GridItem

1、描述 网格容器&#xff0c;由行和列分割的单元格所组成&#xff0c;通过指定“项目”所在的单元格做出各种各样的布局。 子组件 包含GridItem子组件。 3、接口 Grid(scroller?: Scroller) 4、参数 参数名 参数类型 必填 描述 scroller Scroller 否 可滚动组件…

安科瑞智能断路器产品介绍【可监可控 远程操控 短路保护】

开发背景 过去几年智慧用电的产品应用中&#xff0c;大多数只安装于进线测。主要存在以下几个问题&#xff1a;难定位&#xff0c;不知道具体哪个回路出线问题&#xff0c;排查困难&#xff1b;出线过载或线缆温度过高无法知晓&#xff1b;即使是出线回路安装了的场景&#xf…

uniapp+uview 学习笔记(二)—— H5开发

文章目录 前言一、开发步骤1.创建项目2.安装组件库并导入使用3.封装请求4.国际化5.打包 总结 前言 本文主要介绍使用uniapp框架和uview组件库进行H5开发&#xff0c;需要用到的开发工具为HBuilder X。 一、开发步骤 1.创建项目 打开HBuilder X&#xff0c;在顶部栏目选择 新…

英国教育部学生信息中心

你是否曾因学历无法得到国内雇主的认可而感到困扰?别担心,英国教育部学校信息中心为你解忧!作为英国政府官方认可的学历认证机构,其权威性和可靠性广受认可,为留学生求职提供了强大的支持。 一、打破求 职困境:学历真实性认证的重要性 在求职过程中,学历的真实性和有效性是雇…

电脑照片分辨率怎么调?这款dpi修改工具好用

许多考试平台在上传证件照片的时候&#xff0c;大多都会对图片分辨率有具体要求&#xff0c;但是如果遇上手上的图片分辨率达不到要求&#xff0c;那么怎么改图片分辨率呢&#xff1f;可以利用专业的dpi修改工具来处理&#xff0c;比如今天分享的就是一个在线修改图片分辨率的方…

积鼎CFD发动机燃烧仿真,实现航空航天发动机内部燃烧过程的流体仿真

航空航天发动机中的燃烧现象是一种复杂的物理化学过程&#xff0c;包括流动、雾化、相变、传热传质、点火熄火、化学反应、污染物排放、热声振荡和冷却等多个过程&#xff0c;加上燃烧的非定常性和高湍流度&#xff0c;使得准确模拟燃烧过程变得异常困难。在传统CFD模拟需要考虑…

javaSwing推箱子游戏

一、简介 策略性游戏可以锻炼人的思维能力还能缓解人的压力&#xff0c;使人们暂时忘却生活当中的烦恼&#xff0c;增强人们的逻辑思维能力&#xff0c;游戏的艺术美也吸引着越来越多的玩家和厂商&#xff0c;寓教于乐&#xff0c;在放松人们心情的同时还可以活跃双手。在人类…

扩展学习|数字经济与公共管理的相关论文(管理世界)

一是如何建立与数字经济时代相适应的政府监管体制机制&#xff1f; 问题一和二来源&#xff1a;[1]王岭.数字经济时代中国政府监管转型研究[J].管理世界,2024,40(03):110-126204127.DOI:10.19744/j.cnki.11-1235/f.2024.0027. &#xff08;1&#xff09;数字经济时代政府监管转…

ByteTrack多目标跟踪——YOLOX详解

文章目录 1 before train1.1 dataset1.2 model 2 train2.1 Backbone2.2 PAFPN2.3 Head2.3.1 Decoupled Head2.3.2 anchor-free2.3.3 标签分配① 初步筛选② simOTA 2.3.4 Loss计算 项目地址&#xff1a; ByteTrack ByteTrack使用的检测器是YOLOX&#xff0c;是一个目前非常流行…

在 NVIDIA DGX Cloud 上使用 H100 GPU 轻松训练模型

近期&#xff0c;我们正式宣布推出 DGX 云端训练 (Train on DGX Cloud) 服务&#xff0c;这是 Hugging Face Hub 上针对企业 Hub 组织的全新服务。 通过在 DGX 云端训练&#xff0c;你可以轻松借助 NVIDIA DGX Cloud 的高速计算基础设施来使用开放的模型。这项服务旨在让企业 H…

vue2 项目运行 浏览器自动打开 vue项目启动如何自动打开浏览器 vue2取消浏览器自动打开浏览器,vue2关闭自动打开浏览器

1. 找到package.json 2. 找到scripts 在后面添加 --open即可&#xff1a; 3. 运行npm run serve 运行之后&#xff0c;就可以自动打开默认浏览器 4. 同理&#xff0c;不想自动打开 &#xff0c;将 --open 删除即可&#xff01;

【机器学习】基于布谷鸟搜索算法优化的BP神经网络分类预测(CS-BP)

目录 1.原理与思路2.设计与实现3.结果预测4.代码获取 1.原理与思路 【智能算法应用】智能算法优化BP神经网络思路【智能算法】布谷鸟搜索算法&#xff08;CS)原理及实现 2.设计与实现 数据集&#xff1a; 数据集样本总数2000 多输入多输出&#xff1a;样本特征24&#xff0…

选择器加练习

一、常用的选择器 1.元素选择器 语法 : 标签名{} 作用 : 选中对应标签中的内容 例:p{} , div{} , span{} , ol{} , ul{} ...... 2.类选择器(class选择器) 语法 : .class属性值{} 作用 : 选中对应class属性值的元素 注意:class里面的属性值不能以数字开头,如果以符号开头,…

鸿蒙Harmony应用开发—ArkTS-属性动画

组件的某些通用属性变化时&#xff0c;可以通过属性动画实现渐变过渡效果&#xff0c;提升用户体验。支持的属性包括width、height、backgroundColor、opacity、scale、rotate、translate等。布局类改变宽高的动画&#xff0c;内容都是直接到终点状态&#xff0c;例如文字、can…

C++之模版详解

一.array与vector对比 由图发现&#xff0c;使用array数组是必须提前开好空间&#xff0c;而vector是顺序表&#xff0c;可以实现动态开辟空间 array也支持迭代器&#xff0c;如下&#xff1a; int main() {array<int, 10> arr{ 1,2,3,4,5,6,7,8,9,10 };auto it arr.be…

蓝牙HFP协议推荐的语音丢包补偿算法浮点实现的定点化

最近在做蓝牙的宽带语音通话。相对于蓝牙窄带语音&#xff0c;主要变化是把采样率从8k变到16k&#xff0c;以及编解码器从CVSD变成mSBC&#xff08;modified SBC&#xff0c;改进的SBC&#xff09;等。蓝牙语音通话相关的HFP&#xff08;Hand Free Profile&#xff09;强烈建议…