剑指offer——二维数组中的查找(杨氏矩阵)

news2025/1/17 0:17:15

目录

  • 1. 题目描述
  • 2. 常见错误思路
  • 3. 分析
    • 3.1 特例分析
    • 3.2 规律总结
  • 4. 完整代码

1. 题目描述

  • 在一个二维数组中,每一行都按照从左到右递增的顺序排序,每一列都按照从上到下递增的顺序排序。请完成一个函数,输入这样的一个二维数组和一个整数,判断数组中是否含有该整数。
  • 例如下面的二维数组就是每行、每列都递增排序。如果在这个数组中查找数字 7,则返回 true ;如果查找数字 5,由于数组不含该数字,则返回 false。

在这里插入图片描述

2. 常见错误思路

  • 分析这个问题的时候,很多应聘者都会把二维数组画成矩形,从数组中选取一个数字,分3种情况来分析查找的过程。
  • 当数组中选取的数字刚好和要查找的数字相等时,就结束查找过程。如果选取的数字小于要查找的数字,那么根据数组排序的规则,要查找的数字应该在当前选取的位置的右边或者下边(如图2.1(a)所示)。
  • 同样,如果选取的数字大于要查找的数字,那么要查找的数字应该在当前选取的位置的上边或者左边(如图2.1(b)所示).

在这里插入图片描述

  • 注:在数组中间选择一个数(深色方格),根据它的大小判断要查找的数字可能的区域(阴影部分)
  • 在上面的分析中,由于要查找的数字相对于当前选取的位置有可能在两个区域中出现,而且这两个区域还有重叠,这问题看起来就复杂了,于是很多人就卡在这里束手无策了。

3. 分析

3.1 特例分析

  • 当我们需要解决一个复杂的问题时,一个很有效的办法就是从一个具体的问题入手,通过分析简单具体的例子,试图寻找普遍的规律。
  • 针对这个问题,我们不妨也从一个具体的例子入手。下面我们以在题目中给出的数组中查找数字7为例来一步步分析查找的过程。
  • 前面我们之所以遇到难题,是因为我们在二维数组的中间选取一个数字来和要查找的数字做比较,这样导致下一次要查找的是两个相互重叠的区域。如果我们从数组的一个角上选取数字来和要查找的数字做比较,情况会不会变简单呢?
  • 首先我们选取数组右上角的数字9。由于9大于7,并且9还是第4列的第一个(也是最小的)数字,因此7不可能出现在数字9所在的列。
  • 于是我们把这一列从需要考虑的区域内剔除,之后只需要分析剩下的3列(如图22(a)所示)。在剩下的矩阵中,位于右上角的数字是8。
  • 同样8大于7,因此8所在的列我们也可以剔除。接下来我们只要分析剩下的两列即可(如图2.2(b)所示).
  • 在由剩余的两列组成的数组中,数字2位于数组的右上角。
  • 2小于7,那么要查找的7可能在2的右边,也有可能在2的下边。在前面的步骤中,我们已经发现2右边的列都已经被剔除了,也就是说7不可能出现在2的右边,
  • 因此7只有可能出现在2的下边,于是我们把数字2所在的行也别除,只分析剩下的三行两列数字(如图2.2(c)所示)。在剩下的数字中,数字4位于右上角,和前面一样,我们把数字4所在的行也别除,最后剩下两列数字(如图2.2(d)所示)。
  • 在剩下的两行两列 4 个数字中,位于右上角的刚好就是我们要查找的数字 7 ,于是查找过程就可以结束了

在这里插入图片描述

  • 注:矩阵中加阴影背景的区域是下一步查找的范围。

3.2 规律总结

  • 总结上述查找的过程,我们发现如下规律:首先选取数组中右上角的数字。
  • 如果该数字等于要查找的数字,查找过程结束;
  • 如果该数字大于要查找的数字,剔除这个数字所在的列;
  • 如果该数字小于要查找的数字,剔除这个数字所在的行。
  • 也就是说如果查找的数字不在数组的右上角,则每一次都在数组的查找范围中剔除一行或者一列,
  • 这样每一步都可以缩小查找的范围,直到找到要查找的数字,或者查找范围为空

4. 完整代码

  • 把整个查找过程分析清楚之后,我们再写代码就不是一件很难得事了,下面就是上述思路对应的参考代码
#include <stdio.h>
#define ROW 4
#define COL 4

int findnum(int a[ROW][COL], int x, int y, int f)
{
    int i = 0, j = y - 1; //从右上角开始遍历
    while (j >= 0 && i < x)
    {
        if (a[i][j] < f) //比我大就向下
        {
            i++;
        }
        else if (a[i][j] > f) //比我小就向左
        {
            j--;
        }
        else
        {
            return 1;
        }
    }
    return 0;
}

int main()
{
    int a[ROW][COL] = { {1, 2, 8, 9 },
                        {2, 4, 9, 12 },
                        {4, 7, 10, 13 },
                        { 6, 8, 11, 15 } }; //一个示例
    int k = 0;
    scanf("%d", &k);//输入要查找的数字

    if (findnum(a, ROW, COL, k))
    {
        printf("It has been found!\n");
    }
    else
    {
        printf("It hasn't been found!\n");
    }

    return 0;
}
  • 运行结果如下:
  1. 当输入数组中有的数字时:

在这里插入图片描述

    1. 当输入数组没有的数字时:

在这里插入图片描述

  • 在前面的分析中,我们每一次都是选取数组查找范围内的右上角数字。
    同样,我们也可以选取左下角的数字。感兴趣的同学不妨自己分析一下每次都选取左下角的查找过程
  • 但我们不能选择左上角或者右下角。
  • 以左上角为例,最初数字 1 位于初始数组的左上角,由于 1 小于 7 ,那么应该位于 1 的右边或者下边。
  • 此时我们既不能从查找范围内剔除 1 所在的行,也不能剔除 1 所在的列,
  • 这样我们就无法缩小查找范围了

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

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

相关文章

黄金交易策略(Nerve Nnife):大K线对技术指标的影响

我们使用heiken ashi smoothed来做敏感指标&#xff08;大趋势借助其转向趋势预判&#xff0c;但不是马上转变&#xff09;&#xff0c;has默认使用6根k线的移动平均值来做计算的。若在6根k线规范内有一个突变的行情&#xff08;k线很长&#xff09;&#xff0c;那么整个行情的…

基于鲲鹏服务器的LNMP配置

基于鲲鹏服务器的LNMP配置 系统 Centos8 # cat /etc/redhat-release CentOS Linux release 8.0.1905 (Core) 卸载已经存在的旧版本的安装包 # rpm -qa | grep php #查看已经安装的PHP旧版本# rpm -qa | grep php | xargs rpm -e #卸载已经安装的旧版&#xff0c;如果提示有…

CSP-202112-1-序列查询

CSP-202112-1-序列查询 提示&#xff1a;若存在区间[i,j) 满足&#xff1a;f(i)f(i1)…f(j-1)&#xff0c;使用乘法运算 f(i)x(j-i)代替将 f()到 f(j- 1)逐个相加,或可大幅提高算法效率。 一定要看提示&#xff01;单纯的模拟时间会超限&#xff01;算法也是根据提示设计的。 …

【Spring】Bean 的生命周期

一、Bean 的生命周期 Spring 其实就是一个管理 Bean 对象的工厂&#xff0c;它负责对象的创建&#xff0c;对象的销毁等 所谓的生命周期就是&#xff1a;对象从创建开始到最终销毁的整个过程 什么时候创建 Bean 对象&#xff1f;创建 Bean 对象的前后会调用什么方法&#xf…

项目02《游戏-10-开发》Unity3D

【完成本集功能后共享1-10集整套代码】 基于 项目02《游戏-09-开发》Unity3D &#xff0c; 任务&#xff1a;传送至其他场景&#xff0c; 首先在场景中加入传送门&#xff0c; 设置人物标签&#xff0c; using UnityEngine; using UnityEngine.SceneManagement; u…

Tomcat 原理分析

1、Tomcat 的组成 如下图&#xff1a; Tomcat组成 Server&#xff1a; Tomcat 封装的、对外提供完整的、基于组件的 web 服务&#xff0c;包含 Connectors、Container 两个核心组件&#xff0c;以及多个功能组件&#xff0c;各个 Service 之间是独立的&#xff0c;但是共享 同…

C#,十进制展开数(Decimal Expansion Number)的算法与源代码

1 十进制展开数 十进制展开数&#xff08;Decimal Expansion Number&#xff09;的计算公式&#xff1a; DEN n^3 - n - 1 The decimal expansion of a number is its representation in base -10 (i.e., in the decimal system). In this system, each "decimal place…

2024牛客寒假算法基础集训营2部分题解

Tokitsukaze and Bracelet 链接&#xff1a;登录—专业IT笔试面试备考平台_牛客网 来源&#xff1a;牛客网 题目描述 《绯染天空》是一款由 key 社与飞机社共同开发的角色扮演游戏&#xff0c;剧情内容由著名的剧本作家麻枝准编写。它是一款氪金手游&#xff0c;但也有 st…

C++自定义函数详解

个人主页&#xff1a;PingdiGuo_guo 收录专栏&#xff1a;C干货专栏 铁汁们新年好呀&#xff0c;今天我们来了解自定义函数。 文章目录 1.数学中的函数 2.什么是自定义函数 3.自定义函数如何使用&#xff1f; 4.值传递和引用传递&#xff08;形参和实参区分&#xff09; …

ES实战-book笔记1

#索引一个文档,-XPUT手动创建索引, curl -XPUT localhost:9200/get-together/_doc/1?pretty -H Content-Type: application/json -d {"name": "Elasticsearch Denver","organizer": "Lee" } #返回结果 {"_index" : "g…

极狐GitLab 与钉钉的集成实践

DingTalk OAuth 2.0 OmniAuth provider * 引入于 14.5 版本。 您可以使用您的钉钉账号登录极狐GitLab。 登录钉钉开放平台&#xff0c;创建应用。钉钉会生成一个客户端 ID 和密钥供您使用。 登录钉钉开放平台。 在顶部栏上&#xff0c;选择 应用程序开发 > 企业内部开发&am…

修改SpringBoot中默认依赖版本

例如SpringBoot2.7.2中ElasticSearch版本是7.17.4 我希望把它变成7.6.1

物联网数据隐私保护技术

在物联网&#xff08;IoT&#xff09;的世界中&#xff0c;无数的设备通过互联网连接在一起&#xff0c;不断地收集、传输和处理数据。这些数据有助于提高生产效率、优化用户体验并创造新的服务模式。然而&#xff0c;随着数据量的剧增&#xff0c;数据隐私保护成为了一个不能忽…

CSP-202012-1-期末预测之安全指数

CSP-202012-1-期末预测之安全指数 题目很简单&#xff0c;直接上代码 #include <iostream> using namespace std; int main() {int n, sum 0;cin >> n;for (int i 0; i < n; i){int w, score;cin >> w >> score;sum w * score;}if (sum > 0…

力扣刷题之旅:进阶篇(三)

力扣&#xff08;LeetCode&#xff09;是一个在线编程平台&#xff0c;主要用于帮助程序员提升算法和数据结构方面的能力。以下是一些力扣上的入门题目&#xff0c;以及它们的解题代码。 --点击进入刷题地址 一、动态规划&#xff08;DP&#xff09; 首先&#xff0c;让我们来…

Linux中ps/kill/execl的使用

ps命令&#xff1a; ps -aus或者ps -ajx或者 ps -ef可以查看有哪些进程。加上 | grep "xxx" 可以查看名为”xxx"的进程。 ps -aus | grep "xxx" kill命令&#xff1a; kill -9 pid 杀死某个进程 kill -l 查看系统有哪些信号 execl函数&#…

C#上位机与三菱PLC的通信05--MC协议之QnA-3E报文解析

1、MC协议回顾 MC是公开协议 &#xff0c;所有报文格式都是有标准 &#xff0c;MC协议可以在串口通信&#xff0c;也可以在以太网通信 串口&#xff1a;1C、2C、3C、4C 网口&#xff1a;4E、3E、1E A-1E是三菱PLC通信协议中最早的一种&#xff0c;它是一种基于二进制通信协…

再识C语言 DAY17 【什么是原码、反码和补码】

文章目录 前言本文总结于此文章 一、知识补充二、原码三、反码四&#xff0c;补码 总结如果您发现文章有错误请与我留言&#xff0c;感谢 前言 本文总结于此文章 一、知识补充 通常&#xff0c;1字节包含8位。C语言用字节&#xff08;byte&#xff09;表示储存系统字符集所需…

【原理图PCB专题】Cadence17.4 PCB位号重排与反标

在文章:【原理图专题】Cadence 16.6如何把PCB元件位号重排并反标到原理图 中我们讲到了Cadence16.6版本对原理图进行反标的操作。 对于反标之前我们是通过如下所示的绘制流程来讲的,一般在首板或是大改板操作器件里有很多不同的很大的位号,这时我们可以通过Backannotate功能…

kettle--文本文件输出有空格解决方案

在kettle文本文件输出时&#xff0c;不管如何设置字段类型和长度&#xff0c;导出的数据都会有空格&#xff0c;遇到这一问题&#xff0c; 可以在文本文件输出控件中勾选这一项&#xff0c;即可解决这一问题。 文本文件输出&#xff1a;