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

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

                                           ​​​​​​​                    文章所属专栏:《剑指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;
}

  三. 完结散花

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

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

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

我们下期不见不散~~

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

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

相关文章

CSS其他属性

文章目录 1. vertical-align1.1. 概念1.2. 常用值1.3. 作用1.4. 出现的情况一1.4.1. 原因1.4.2. 解决方案 1.5. 出现情况二1.5.1. 解决方案一1.5.2. 解决方案二1.5.3. 解决方案三 1.6. 出现情况三1.6.1. 原因1.6.2. 解决方案 2. 溢出效果2.1. 作用2.2. 属性名 3. 隐藏效果3.1. …

买卖股票的最佳时机1,2,3

买卖股票的最佳时机 力扣题目链接 dp[i][0] 表示第i天持有股票所得最多现金 定义二维数组 两列 &#xff1a;0代表持有股票 1代表不持有股票 行代表第几天 dp[i][0] max(dp[i - 1][0], -prices[i]); 第i天持有股票&#xff1a;两种情况 第一种是昨天就已经持有股票了 所…

NVM使用教程

文章目录 ⭐️写在前面的话⭐️1、卸载已经安装的node2、卸载nvm3、安装nvm4、配置路径以及下载源5、使用nvm下载node6、nvm常用命令7、全局安装npm、cnpm8、使用淘宝镜像cnpm9、配置全局的node仓库&#x1f680; 先看后赞&#xff0c;养成习惯&#xff01;&#x1f680;&#…

探索AI+电商领域应用与发展

AI火的已经一塌糊涂了&#xff0c;已经有很大一部分的企业和个人已经坐上了这趟超音速列车&#xff0c;但对于电商领域具体都有哪些助理&#xff0c;目前为止还是比较散&#xff0c;今天来顺一下AIGC之与电商到底带来了些什么&#xff1f; 一、什么是AIGC AIGC是内容生产方式…

个人开发者上架App流程

摘要 个人开发者完全可以将自己开发的App上传至应用商店进行上架。本文将介绍上架流程的通用步骤&#xff0c;包括确定App功能和定位、准备相关资料、开发App、提交审核、发布App和宣传推广等内容。 引言 个人开发者在如今的移动应用市场中也有机会将自己的作品推向更广泛的…

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…

重生奇迹MU 的全部地图

卓越首饰类&#xff1a;火项链、毒戒指——海1小巴、美人鱼、卡2门口&#xff0c;卡1最里面&#xff0c;地3等等 雷项链&#xff0c;冰戒指——海1蓝翼怪&#xff0c;卡2龙虾以上&#xff0c;失落3&#xff08;门口黄金点哦&#xff0c;盛产冰戒指&#xff09;等等 冰项链——…

第十二届蓝桥杯省赛CC++ 研究生组-货物摆放

还是整数分解问题,注意n本身也是约数 #include <iostream> int main(){printf("2430");return 0; }#include <iostream> #include<cmath> #include<algorithm> using namespace std; typedef long long ll; const ll n 2021041820210418LL…

Jenkins 一个进程存在多个实例问题排查

Jenkins 一个进程存在多个实例问题排查 最近Jenkins升级到2.440.1​版本后&#xff0c;使用tomcat​服务部署&#xff0c;发现每次定时任务总会有3-4个请求到我的机器人上&#xff0c;导致出现奇奇怪怪的问题。 问题发现 机器人运行异常&#xff0c;总有好几个同时请求的服务。…

宋仕强论道之华强北科技创新说

宋仕强论道之华强北科技创新说&#xff0c;“创新”是深圳市和华强北灵魂&#xff0c;创新再加上敢想敢干永不言败&#xff0c;造就了深圳市经济奇迹和华强北财富神话&#xff01;首次在深圳市落槌的“土地拍卖”&#xff0c;华强北“一米柜台”赋予独立经营权&#xff0c;把最…

TCP协议中的传输控制机制图文详解「重传机制」「流量控制」「拥塞控制」

目录 TCP重传机制 超时重传 快速重传 SACK 方法 Duplicate SACK TCP 流量控制 滑动窗口 累积确认 窗口大小由哪一方决定&#xff1f; 接收窗口和发送窗口的大小是相等的吗&#xff1f; 流量控制 窗口关闭的后果 糊涂窗口综合症 TCP拥塞处理 为什么要有拥塞控制呀&#xff0c;不…

高速CAN 收发器AMIS30660CANH2RG 用于各种数据传输协议的调制解调器和收发器

AMIS30660CANH2RG CAN 收发器是控制器区域网络 (CAN) 协议控制器和物理总线之间的接口&#xff0c;可在 12 V 和 24 V 系统中使用。该收发器为总线提供差分发射功能&#xff0c;向 CAN 控制器提供差分接收功能。由于接收器输入较宽的共模电压范围和其他设计功能&#xff0c; 能…

Python爬取豆瓣电影Top 250,豆瓣电影评分可视化,豆瓣电影评分预测系统

博主介绍&#xff1a;✌程序员徐师兄、7年大厂程序员经历。全网粉丝12w、csdn博客专家、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战✌ &#x1f345;文末获取源码联系&#x1f345; &#x1f447;&#x1f3fb; 精彩专栏推荐订阅&#x1f447;…

C++ 模板入门详解

目录 0. 模板引入 1.函数模板 1. 函数重载的缺点 2. 函数模板的概念和格式 2. 函数模板的实例化 2.1 隐式实例化&#xff1a;让编译器根据实参推演模板参数的实际类型 2.2 显式实例化&#xff1a;在函数名后的<>中指定模板参数的实际类型 2.3 函数模板参数的匹…

[HFCTF 2021 Final]easyflask

[HFCTF 2021 Final]easyflask [[python反序列化]] 首先题目给了提示&#xff0c;有文件读取漏洞&#xff0c;读取源码 #!/usr/bin/python3.6 import os import picklefrom base64 import b64decode from flask import Flask, request, render_template, sessionapp Flask(_…

【Leetcode-54.螺旋矩阵】

题目&#xff1a; 给你一个 m 行 n 列的矩阵 matrix &#xff0c;请按照 顺时针螺旋顺序 &#xff0c;返回矩阵中的所有元素。 示例 1&#xff1a; 输入&#xff1a;matrix [[1,2,3],[4,5,6],[7,8,9]] 输出&#xff1a;[1,2,3,6,9,8,7,4,5]示例 2&#xff1a; 输入&#xff1…

MySQL分组查询与子查询 + MySQL表的联结操作

目录 1 MySQL分组查询与子查询 1.1 数据分组查询 1.2 过滤分组 1.3 分组结果排序 1.4 select语句中子句的执行顺序 1.5 子查询 2 MySQL表的联结操作 2.1 关系表 2.2 表联结 2.3 笛卡尔积 2.4 内部联结 2.5 外联结 2.6 自联结 2.7 组合查询 1 MySQL分组查询与子查询…

如何把1G多的视频压缩到500兆以内?轻松节省内存空间~

微信已经成为了我们上班交流沟通时必不可少的通讯工具之一&#xff0c;在使用微信时&#xff0c;常常会遇到系统提示发送的word、ppt、pdf文件、视频、压缩包等文件超过1G&#xff0c;无法发送。有没有什么办法可以缩小文件的体积呢&#xff1f;今天给大家介绍几款可以用于视频…

基于python+vue研究生志愿填报辅助系统flask-django-php-nodejs

二十一世纪我们的社会进入了信息时代&#xff0c;信息管理系统的建立&#xff0c;大大提高了人们信息化水平。传统的管理方式对时间、地点的限制太多&#xff0c;而在线管理系统刚好能满足这些需求&#xff0c;在线管理系统突破了传统管理方式的局限性。于是本文针对这一需求设…

10BASE-T1S协议基本介绍

10BASE10Base-T1S 是 IEEE 802.3cg 标准的一部分&#xff0c;该标准支持单根双绞线高达 10 Mbps 的数据速率&#xff0c;适用于长达 25 米半双工网络&#xff0c;旨在实现多点网络上的无碰撞、确定性传输。 1、网络拓扑图和ECU连接方式 网络架构支持多播总线式架构&#xff0c…