数组

  • 数组最简单的是数据结构,占据一整块连续的内存并按照顺序存储数据,创建数组时候,我们需要首先指定数组的容量大小,然后根据大小分配内存。即使我们只在数组中存储一个元素,亚需要为所有数据预先分配内存,因此空间使用效率差,经常会有空闲区域没有得到充分利用。
  • 由于数组中内存是连续的,于是可以根据下标在O(1)时间内读/写任何元素,因此时间效率很高。
  • 为解决数组空间效率问题,人们设计实现了多种动态数组,Java中的vector。为了避免浪,我们先为数组开辟一个较小的空间,然后向数组添加元素的过程中,当元素个数超过数组容量的时候,我们会重新分配一个更大的空间,接着吧之前的数据复制到新的驻足中,在将之前的内存释放,这样就能减少内存的浪费。但是每一层扩充数组容量都有大量的额外操作,这多时间性能有负面的影响,因此使用动态数组时候要尽量减少改变数组容量大小的次数。

算法题:二维数组中查找

  • 题目:在一个二维数组中,每一行从左到右递增顺序存储,每一列都按照从上到下递增顺序排序。完成一个函数,输入这样一个二维数组和一个整数,输出数组中是否包含改整数以及改整数的位置。
  • 分析过程如下: 例如下面二维数组,每行,列都递增。如果这个数组中查找数字6,则返回true,位置(2,1)。如果查找数字5返回false

1 2 3 4 5
2 4 6 8 10
3 6 9 12 15
4 8 12 16 20

错误解法分析过程如下
  • 按照题目要求,每列,行都递增,如上,通过观察以上矩阵的特性,很多同学会采用二分法,步骤如下:

    • 将二维数组看成是一个现象的结构,总共有20个元素,left=0,right=20, mid= (left+right)/2=10
    • 取中间位置元素值value与目标元素key比较
    • value == key 则得出结果
    • value < key则left = mid + 1
    • value > key 则right = mid - 1
    • 具体实现如下
/*** 错误案例* @author liaojiamin* @Date:Created in 13:59 2020/10/30*/
public class FindOne {public static Integer[][] getTwoDimenArray(int rows, int cloumns){Integer[][] twoDimen = new Integer[rows][cloumns];for (int i = 0; i < rows; i++) {for (int j = 0; j < cloumns; j++) {Integer key = (i+1) * (j+1);twoDimen[i][j] = key;System.out.print(key + "  ");}System.out.println("");}return twoDimen;}public static void findOneInTwoDimenArray1(int rows, int cloumns, Integer key){if(rows <=0 || cloumns <=0){return;}Integer[][] twoDimen = getTwoDimenArray(rows, cloumns);if(twoDimen == null){return;}boolean isInArray = false;int keyCloumns = -1;int keyRows = -1;int left = 0;int right = rows * cloumns -1;int col = cloumns;while (left <= right){int mid = (left + right) / 2;Integer value = twoDimen[mid/ col][mid%col];//中间位置if(value == key){keyRows = mid/col;keyCloumns = mid%col;isInArray = true;break;}else if(value < key){left = mid + 1;}else {right = mid - 1;}}System.out.println("isInArray: "+ isInArray + "  position: rows:" +keyRows + " cloums:" + keyCloumns);}public static void main(String[] args) {findOneInTwoDimenArray1(4, 5, 8);}
}
  • 以下测试案例:
//测试一:正确
inPut:4,5,8
outPut:
1  2  3  4  5
2  4  6  8  10
3  6  9  12  15
4  8  12  16  20
isInArray: true  position: rows:1 cloums:3
//测试二:错误
input:5,4,8
1  2  3  4
2  4  6  8
3  6  9  12
4  8  12  16
5  10  15  20
isInArray: false  position: rows:-1 cloums:-1
  • 如上测试用例可知,以上解法是错误的,原因在于虽然此二维数组每一列每一行都递增,当并不代表中间元素mid之前的元素一定小于mid导致程序出错。
正确解法分析过程如下
  • 还是将二维数组看成矩阵,,从中选一个元素 m与目标值key比较,分三种情况分析查找,

    • 情况一 当 m == key,结束查找
    • 情况二 当 m < key,根据数组排序规则,要查找的数字应该在当前选区的位置的右边或者下面
    • 情况三 当m > key,同样的,要查的数字应该在左边或者上面

  • 如上分析,由于需要朝招的数字相对当前选取的m的位置有可能两个区域,而且有重叠,这样看起来就复杂了。

  • 我们将问题具体化,。下面以上图中矩阵中查找数字7 为案例,一步步分析查找过程。

  • 之前之所以困难,是我们在二维数组的中间选取的数字m 与目标值key比较,这样导致下一次需要查找的两个相互重叠的区域。如果我们从数组的一个角上选取,情况如下:

    • 首先选右上角数字9, 9 > 7,并且9 还在第四列的第一个数字,所有,7 不可能在第四列

    • 将剩下三列看成一个新的二维数组,同样选右上角 8 > 7 ,同样可以排除第三列数

    • 将剩下两列看成一个新二维数组,同样选右上角2 < 7,那么要查找的7 可能在2的右边也可能在2 的下面,因为之前的操作已经将右边的所有数据都排除了,所有必定在2 的下面,并且将2 这一行踢出,只剩下3*2 的二维数组,如下

    • 剩下上图中,同样用这个方法,去右上角4 < 7 ,所以不再这一行,可能在4下面,剩下2*2 的二维数组

  • 接着在取右上角 7 = 7 得出最终答案。

总结
  • 以上查找过程,有如下规律:首先选取数组中右上角元素,

    • 如果改数字等于要查找数字,结束查找
    • 如果改数字小于要查找数字,踢出这个数字所在行
    • 如果这个数字大于要查找的数字,踢出这个数字所在的列
    • 依次每一步都在查找范围内踢出一列或者一行,逐步缩小范围。直到查询到或者为空。
    • 如下代码实现。
    • 时间复杂度 O(max(rows, cloumns)),空间复杂度 O(1)
/*** * @author liaojiamin* @Date:Created in 13:59 2020/10/30*/
public class FindOne {public static Integer[][] getTwoDimenArray(int rows, int cloumns){Integer[][] twoDimen = new Integer[rows][cloumns];for (int i = 0; i < rows; i++) {for (int j = 0; j < cloumns; j++) {Integer key = (i+1) * (j+1);twoDimen[i][j] = key;System.out.print(key + "  ");}System.out.println("");}return twoDimen;}public static void findOneInTwoDimenArray2(int rows, int cloumns, Integer key){if(rows <=0 || cloumns <=0 || key == null){return;}Integer[][] twoDimen = getTwoDimenArray(rows, cloumns);if(twoDimen == null){return;}boolean isInArray = false;int keyCloumns = cloumns -1;int keyRows =0;while (keyCloumns >= 0 && keyRows < rows){if(twoDimen[keyRows][keyCloumns] == key){System.out.println("isInArray: "+ isInArray + "  position: rows:" +keyRows + " cloums:" + keyCloumns);break;}else if(twoDimen[keyRows][keyCloumns] > key){keyCloumns --;}else {keyRows ++;}}}public static void main(String[] args) {findOneInTwoDimenArray2(5, 4, 8);}
}
  • 测试用例:

    • 二维数组中查找包含的数字,数组中最大值,最小值,介于最大最小之间的值
    • 二维数组中查找不包含的数字,大于最大值,小于最小值,介于最大最小之前的不存在的值
    • 特殊输入 null
其他思路
  • 以上是去右上角的数字,统一,可以选左下角的数字,
  • 不能选左上角的数字,例如选择1, 1 < 7 ,那么7 位于1 的下面或者右边,没有参考意义。
  • 不能选右下角的数字,例如15 , 15 > 7,那么7 位于15 的上面或者左边,没有参考意义。

上一篇 数据结构与算法–实现Singleton模式
下一篇:数据结构与算法–字符串:字符串替换

数据结构与算法--数组:二维数组中查找相关推荐

  1. 【数据结构与算法】二维数组中的查找(剑指offer)java版

    在一个二维数组中(每个一维数组的长度相同),每一行都按照从左到右递增的顺序排序,每一列都按照从上到下递增的顺序排序.请完成一个函数,输入这样的一个二维数组和一个整数,判断数组中是否含有该整数. 分析 ...

  2. 02_JavaScript数据结构与算法(二)数组

    JavaScript 数据结构与算法(二)数组 几乎所有的编程语言都原生支持数组类型,因为数组是最简单的内存数据结构. 数组通常情况下用于存储一系列同一种数据类型的值. 但在 JavaScript 里 ...

  3. 数组(一维数组、多维数组/二维数组)和简单排序算法

    提示:数组是线性数据结构中最为基础,最为典型的一种顺序型结构. 它用一组连续的内存空间 ,来存储一组具有相同类型的数据. 与变量相比,变量是一种单一的数据存储方式,而数组是用于存储一连串的一组数据. ...

  4. 【C 语言】二级指针内存模型 ( 指针数组 | 二维数组 | 自定义二级指针 | 将 一、二 模型数据拷贝到 三 模型中 并 排序 )

    文章目录 一.指针数组 和 二维数组 数据 拷贝到 自定义二级指针 中 1.函数形参 设计规则 2.三种内存模型 对应 函数形参 指针退化规则 二.完整代码示例 一.指针数组 和 二维数组 数据 拷贝 ...

  5. python二维数组去重复_python 去除二维数组/二维列表中的重复行方法

    python 去除二维数组/二维列表中的重复行方法 之前提到去除一维数组中的重复元素用unique()函数,如果要去除二维数组中的重复行该怎么操作呢? import numpy as np arr = ...

  6. c/c++教程 - 1.7 数组 一维数组 二维数组

    九.数组 数组:一个里面存放了相同类型数据元素的集合. 特点:每个数组中的元素都是相同的数据类型:数组是由连续的内存位置组成的. 注意:数组的下标是从0开始索引. 参考视频:https://www.b ...

  7. C语言数组——二维数组

    C语言目录 C/C++学习资源(百度云盘链接) 计算机二级资料(过级专用) C语言学习路线(从入门到实战) 编写C语言程序的7个步骤和编程机制 C语言基础-第一个C程序 C语言基础-简单程序分析 VS ...

  8. C# 指定格式的字符串截成一维数组(二维数组)的操作类

    指定格式的字符串截成一维数组(二维数组)的操作类 做项目时经常会遇到将"1,3,a,b,d"截成一维数组或将"1,a;2,b;3,c;4,d"截成二维数组.虽然 ...

  9. php 二位数组随机,PHP多维数组 php打乱数组二维数组多维数组的简单实例

    php中的shuffle函数只能打乱一维数组,有什么办法快速便捷的打乱多维数组?手册上提供了 上面这个是针对二维数组的! 下面针对多维数组的乱序方法?尽可能的方便快速: 以下函数也是出自php手册,可 ...

  10. php 数组重新打乱_php打乱数组二维数组多维数组的简单实例

    php中的shuffle函数只能打乱一维数组,有什么办法快速便捷的打乱多维数组?手册上提供了 function shuffle_assoc($list) { if (!is_array($list)) ...

最新文章

  1. 无法嵌入互操作类型...请改用适用的接口 解决办法
  2. mysql数据库性别男用1存储那性别女用什么呢?
  3. pytorch安装问题:路径不对导致no moduled name 'torch'
  4. Oracle使用impdb/expdb数据泵导入/导出数据库
  5. lesson7 集合set
  6. php禁用cookie后session设置方法分析
  7. 程序=数据结构+算法
  8. jquery ajax 数据传输
  9. AltiumDesigner17快捷键
  10. 100个MySQL 的调节和优化的提示
  11. java spark 环境_在 IntelliJ IDEA 中配置 Spark(Java API) 运行环境
  12. linux的/proc文件_Linux中“ / proc”文件系统指南
  13. 小学计算机课教案多变的刷子,信息技术《多变的刷子工具》教学设计.doc
  14. 永恒之蓝-MS17010 CVE-2017-0146
  15. 如何掌握电烙铁焊接技术
  16. 电影票房预测-kaggle项目Python项目
  17. Zookeeper 简介
  18. autojs安卓10,11泡椒云提示无法读取imei码解决方案
  19. 赵小楼《天道》《遥远的救世主》解读(1)怎么评价《遥远的救世主》《天幕红尘》这两本书和《天道》这部电视剧?
  20. Intune在个人设备中保护企业数据的MAM解决方案

热门文章

  1. C和指针之字符串编程练习10(判断字符串是否是回文数)
  2. 【C语言简单说】三:整数变量和输出扩展(1)
  3. linux tcp 内核模块,C – Linux – 内核模块 – TCP头
  4. bat从数组中找出相同数字并删除_找到所有数组中消失的数字
  5. “爱因斯坦兄弟”事件轰动纽约时报!双胞胎乱写博士论文,整容后越黑越红,竟然名利双收..........
  6. 被夸了几十年,地球都要因为它变秃了,你还天天用它......
  7. 连破四次吉尼斯世界纪录!厨师界再出神人,用一公斤拉面缔造了一代传奇,背后却是简单的原理……
  8. 少儿编程教育是“揠苗助长”还是要培养未来的程序员?
  9. 入门机器学习,这一步必不可少!
  10. java里面什么时候环境变量_Java的环境变量什么时候需要设置?