📌导航小助手📌
🖋总结🖋
📖前面的话📖
本专栏介绍的是 牛客网 上面的两道题解,同时 解题所用语言均为 Java语言 ~
牛客网链接:🚘牛客网直通车🚘
🔒题目一:二维数组中的查找🔒
✨题目链接:二维数组中的查找✨
🔐题目描述🔐
在一个二维数组array中(每个一维数组的长度相同),每一行都按照从左到右递增的顺序排序,每一列都按照从上到下递增的顺序排序。请完成一个函数,输入这样的一个二维数组和一个整数,判断数组中是否含有该整数。
[[1,2,8,9],
[2,4,9,12],
[4,7,10,13],
[6,8,11,15]]
给定 target = 7,返回 true。
给定 target = 3,返回 false。
示例1:
输入:7,[[1,2,8,9],[2,4,9,12],[4,7,10,13],[6,8,11,15]]
返回值:true
说明:存在7,返回true
示例2:
输入:1,[[2]]
返回值:false
示例3:
输入:3,[[1,2,8,9],[2,4,9,12],[4,7,10,13],[6,8,11,15]]
返回值:false
说明:不存在3,返回false
💡解题思路
思路一:
遍历二维数组,在期间进行判断,如果找到目标值,返回 true,如果找不到目标值,返回 false ~
缺点:效率低下 ~
思路二:
通过每一次查找,都会排除多个元素;
通过观察,我们可以发现,每一行的最右上角的元素 都是该行的最大值,都是该列的最小值 ~
以所给的描述中的二维数组为例,假设此时所要查找的目标值是 7,那么,此时要比最右上角的值9 要小,就说明 目标值肯定不在该列(因为该列的最小值就是 最右上角的值9,目标值比这一列最小的值还要小),那么 此时就可以排除这一列的值了 ~
同样的道理,如果目标值要比最右上角的值还要大,就说明目标值就不再这一行,这样就直接排除了一行的值 ~
此时,此时查找的效率就相对于比较高了 ~
这种思路要考虑一下临界条件 !!!
🔑源代码
public class Solution {
//二维数组的查找
public boolean Find(int target, int [][] array) {
//判断二维数组为null 或者 数组长度为 0 (非法情况)
if(array == null || array.length == 0){
return false;
}
//i、j表示的是数组的下标
//i表示行,j表示列
int i = 0;
int j = array[0].length - 1;
while (i<array.length && j>=0){
//目标值大于最右边的值
if(target > array[i][j]) {
//不可能出现在这一行
i++;
}
else if(target < array[i][j]) {
j--;
}
else {
return true;
}
}
return false;
}
}
🖋总结🖋
- 需要注意的是 非法的情况:一是数组为 null,二是数组长度为 0;
- 需要注意的是 二维数组中,第一行的长度可以用 array[0].length 来表示 ~
🔒题目二:旋转数组的最小数字🔒
✨题目链接:旋转数组的最小数字✨
🔐题目描述🔐
有一个长度为 n 的非降序数组,比如[1,2,3,4,5],将它进行旋转,即把一个数组最开始的若干个元素搬到数组的末尾,变成一个旋转数组,比如变成了[3,4,5,1,2],或者[4,5,1,2,3]这样的。请问,给定这样一个旋转数组,求数组中的最小值。
要求:空间复杂度:O(1),时间复杂度:O(logn) 。
示例1:
输入:[3,4,5,1,2]
返回值:1
示例2:
输入:[3,100,200,3]
返回值:3
💡解题思路
思路一:
遍历整个数组,遍历期间,定义一个最小值,如果数组中的哪个元素要比最小值还要小,自动更新 ~
思路二:
由于数组非递减,而且是旋转过来的;
[1,2,3,4,5] --> [4,5,1,2,3]
所以可以比较 当前值和下一个值的大小,如果当前值 <= 下一个值,那么就是正确的,可以换下一个;如果当前值 >= 下一个值的大小(第一次大于),那么就说明 下一个值就是我们要找的最小元素 ~
思路三:
不管怎么旋转数组,得到的数组都可以把它看成两个 "非递减的" 部分,只是由于旋转次数的不同,最小值时在中间值的左边或右边或正好就是中间值罢了;
同时,前半部分的值 要在整体上 > 后半部分的值 ;
🔑源代码
import java.util.*;
import java.util.ArrayList;
public class Solution {
public int minNumberInRotateArray(int [] array) {
//合法性判断
if (array == null || array.length == 0) {
return 0;
}
int left = 0;
int right = array.length - 1;
int mid = 0;
while(array[left] >= array[right]) {
//如果两个元素已经相邻了,说明最右侧的值一定是要找的值
if(right - left == 1) {
mid = right;
break;
}
//左边值 == 中间值 == 右边值 的情况
if(array[left] == array[right] && array[left] == array[mid]) {
int result = array[left];
//一个一个遍历
for (int i = left + 1; i < right; i++) {
if(result > array[i]) {
result = array[i];
}
}
return result;
}
//更新 mid 的值
mid = (right + left) >> 1;
//如果中间值 >= 左半部分的值,就说明 最小的值在右半部分,这就直接把左半部分的值给排除了
if(array[mid] >= array[left]) {
left = mid;
}
else {
right = mid;
}
}
return array[mid];
}
}
🖋总结🖋
- 该题仍然是查找类型的题目,如果一次可以排除多个元素显然是更好
- 在使用二分查找的时候,需要另起判断 是否左中右值相等的情况
这篇博客就写到这里啦 ~
如果觉得写得不错的老铁们,一键三连起来吧 ~