目录
二维数组中的查找
题目链接:二维数组中的查找
题目描述
在一个二维数组array中(每个一维数组的长度相同),每一行都按照从左到右递增的顺序排序,每一列都按照从上到下递增的顺序排序。请完成一个函数,输入这样的一个二维数组和一个整数,判断数组中是否含有该整数。
[
[1,2,8,9],
[2,4,9,12],
[4,7,10,13],
[6,8,11,15]]
给定 target = 7,返回 true。
给定 target = 3,返回 false。
数据范围:矩阵的长宽满足 0 <= n, m <= 500 , 矩阵中的值满足 0 <= val <= 10^9
进阶:空间复杂度 O(1),时间复杂度 O(n+m)
解题思路
一种简单的做法即利用两个for循环遍历一遍二维数组,找出是否存在待查找数字即,但其时间复杂度太高了,O(n^2)。
根据题目描述可知,二维数组的每一行都按照从左到右递增的顺序排序,每一列都按照从上到下递增的顺序排序,因此可以根据这个二维数组的规律来写出一种时间复杂度为O(m+n)的解法.
例如上述二维数组,要查找的数字为10,根据其规律,从右上角的9开始比较,具体比较步骤为:①首先与9比较,大于9,则继续与12进行比较;
②12大于10,因此根据规律肯定在12左边,则与9进行比较;
③9小于10,因此肯定在9的下方,再与10进行比较;
④10等于10,成功查找到,返回true
具体代码
public class Solution {
public boolean Find(int target, int [][] array) {
int rows = array.length;
if(rows == 0) {
return false;
}
int cols = array[0].length;
if(cols == 0) {
return false;
}
int row = rows - 1;
int col = 0;
while(col < cols && row >= 0) {
if(array[row][col] > target) {
row--;
}else if(array[row][col] < target) {
col++;
}else {
return true;
}
}
return false;
}
}
旋转数组的最小数字
题目链接:旋转数组的最小数字
题目描述:
有一个长度为 n 的非降序数组,比如[1,2,3,4,5],将它进行旋转,即把一个数组最开始的若干个元素搬到数组的末尾,变成一个旋转数组,比如变成了[3,4,5,1,2],或者[4,5,1,2,3]这样的。请问,给定这样一个旋转数组,求数组中的最小值。
数据范围:1≤n≤10000,数组中任意元素的值: 0≤val≤10000
要求:空间复杂度:O(1),时间复杂度:O(logn)
解题思路
思路①:当然是遍历了,遍历整个数组求出最小值即可,但是时间复杂度是O(n),显然不满足题目要求.
思路②:根据题意,原始数组是非降序的,其旋转后就会出现递减的,而引起递减的数字,就是这个数组中的最小值.
可以利用二分思想来解决该问题,定义出首尾下标,left=0,right=arr.length-1,mid为(left+right)/2.因为是非递减数组旋转,因此旋转后数组分为两个部分,左部分是递增,右部分也是递增,只有两个部分相交的地方是递减,因此右边那个数据就是这个旋转数组的最小值
具体步骤:
①如果mid下标的值大于left下标的值,说明这个最小值在mid的右半部分,因此,令left = mid,直接舍去左半部分;
②如果mid下标的值小于left下标的值,说明这个最小值在mid的右半部分,因此,令left = mid,直接舍去左半部分;
这样不断判断,不断缩小范围,left永远在前半部分,而right永远在后半部分,当right和left相邻时,right下标的值即为整个数组的最小值.
③但是也可能存在一种比较特殊的情况,题目中要求的是非降序数组,因此也可能出现有相等的值,此时就需要以线性探测的方式来寻找最小值了
就比如上面这种情况,此时就无法通过上面的方法来寻找最小值,就需要以线性探测的方式来寻找.
具体代码
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[mid] == array[left] && array[mid] == array[right]) {
int ret = array[left];
for(int i = left + 1; i < right; i++) {
if(ret > array[i]) {
ret = array[i];
}
}
return ret;
}
mid = left + ((right - left) >> 1);
if(array[mid] >= array[left]) {
left = mid;
}else {
right = mid;
}
}
return array[mid];
}
}
调整数组顺序使奇数位于偶数前面
题目链接:调整数组顺序使奇数位于偶数前面
题目描述:
输入一个整数数组,实现一个函数来调整该数组中数字的顺序,使得所有的奇数位于数组的前半部分,所有的偶数位于数组的后半部分,并保证奇数和奇数,偶数和偶数之间的相对位置不变。
解题思路
根据题目要求,要保证相对位置不变,因此不能利用双指针分别从左和右依次寻找奇数和偶数,并对其进行交换.对于该问题的解决可以借鉴插入排序思想.
例如下图数据
定义一个k来表示目前已经有几个奇数放在了应该放的位置,在之后的移动数据中,就不需要移动这几个数据,以上述数据为例,第一次交换后,k = 1,未发生位置交换.
在第二次寻找到奇数,此时j = 2, k = 1,根据代码思想,其将3之前的偶数全部后移一位,将空闲的位置再赋值为3即可.
一直根据这种思想来进行交换,最终即可得到所求的结果
具体代码
public class Solution {
public void reOrderArray(int [] array) {
int k = 0;
for(int i = 0; i < array.length; i++) {
if((array[i] & 1) == 1) {
int tmp = array[i];
int j = i;
while(j > k) {
array[j] = array[j-1];
j--;
}
array[k++] = tmp;
}
}
}
}
数组中出现次数超过一半的数字
题目链接:数组中出现次数超过一半的数字
题目描述:
给一个长度为 n 的数组,数组中有一个数字出现的次数超过数组长度的一半,请找出这个数字。
例如输入一个长度为9的数组[1,2,3,2,2,2,5,4,2]。由于数字2在数组中出现了5次,超过数组长度的一半,因此输出2。
数据范围:0<=n<=50000,数组中元素的值 0≤val≤10000
要求:空间复杂度:O(1),时间复杂度:O(n)
解题思路1
可以直接利用map来统计,建立<数字,次数>的映射关系,统计每个字符出现的次数,找到出现次数超过一半的那个,输出数字即可
import java.util.*;
public class Solution {
public int MoreThanHalfNum_Solution(int [] array) {
if(array == null || array.length == 0) {
return 0;
}
Map<Integer, Integer> map = new HashMap<>();
for(int i = 0; i < array.length; i++) {
if(map.containsKey(array[i])) {
int count = map.get(array[i]);
count++;
map.put(array[i], count);
}else {
map.put(array[i], 1);
}
if(map.get(array[i]) > array.length/2) {
return array[i];
}
}
return 0;
}
}
解题思路2
先对数组进行排序,其出现次数超过一半的数字一定是在中间位置,因为题目保证一定会有结果,因此直接返回数组中间位置的数字即可.
public class Solution {
public int MoreThanHalfNum_Solution(int [] array) {
if(array == null || array.length == 0) {
return 0;
}
Arrays.sort(array);
return array[array.length/2];
}
}
解题思路3
要求的是出现次数超过一半的数字,这种解题思路的大致思想是每次删除掉相同的两个数字,到最后剩下的那个数字就是要求的数字,最终再将这个数字代入到原数组遍历一遍统计一下出现次数,保证结果的正确性.以下列数组为例:
例如当i处于下图位置时,此时target和times分别为
当for循环遍历结束后,此时此时target和times分别为
此时可以确定,出现次数超过一半的数字就是2,再将其代入原数组中遍历一遍确定一下结果即可
import java.util.*;
public class Solution {
public int MoreThanHalfNum_Solution(int [] array) {
if(array == null || array.length == 0) {
return 0;
}
int target = array[0];
int times = 1;
for(int i = 1; i < array.length; i++) {
if(times == 0) {
target = array[i];
times = 1;
}else if(array[i] == target) {
times++;
}else {
times--;
}
}
times = 0;
for(int i = 0; i < array.length; i++) {
if(target == array[i]) {
times++;
}
}
return times > array.length/2 ? target : 0;
}
}