[leetcode]第 5 天 查找算法(中等)
04. 二维数组中的查找
思路
直接遍历!两个for循环
class Solution {
public boolean findNumberIn2DArray(int[][] matrix, int target) {
for(int[] row : matrix){
for(int e : row){
if(e == target) return true;
}
}
return false;
}
}
很显然不够优雅,且时间复杂度为O(NM)。。看看有没有更好的解法。。
大佬提供了标志数法。就是将矩阵旋转45°,类似于二叉搜索树,因此从根节点开始搜索,遇到比target大的元素就向左,反之向右。
以matrix左下角元素为标志数flag
- flag > target,则target在flag所在行上方,消去flag所在行
- flag < target,则target在flag所在列右方,消去flag所在列
流程:
- 从(i, j)开始遍历
若matrix[i][j] > target,i--
若matrix[i][j] < target,j++
若matrix[i][j] = target,返回true - 索引越界,返回false
时间复杂度O(M+N)
class Solution{
public boolean findNumberIn2DArray(int[][] matrix, int target){
int i = matrix.length - 1, j = 0;
while(i >= 0 && j < matrix[0].length){
if(matrix[i][j] > target) i--;
else if(matrix[i][j] < target) j++;
else return true;
}
return false;
}
}
11. 旋转数组的最小数字
思路
经过两小时的历练我还是选择了循环。。。
class Solution {
public int minArray(int[] numbers) {
int a = numbers[0];
for(int i = numbers.length - 1 ; i >= 0; i--){
if(a > numbers[i]) a = numbers[i];
}
return a;
}
}
很明显不够优雅,评论区给了二分法的解法。
原来在旋转数组里也可以使用二分查找吗><!
流程还是三部曲:
- 初始化
i, j分别指向数组的左右两端 - 循环二分
m = (i + j)/2; - nums[m] > nums[j],m在左子组中,旋转点x在[m + 1, j] 中, i = m + 1;
- nums[m] < nums[j],m在右子组中,旋转点x在[i, m - 1] 中, j = m;
- nums[m] = nums[j],无法判断旋转点在哪,因为可能是[2, 2, 0, 1, 2],所以j = j - 1;
- 返回值:i = j时跳出循环,返回nums[i]
class Solution {
public int minArray(int[] numbers) {
int i = 0, j = numbers.length - 1;
while (i < j) {
int m = (i + j) / 2;
if (numbers[m] > numbers[j]) i = m + 1;
else if (numbers[m] < numbers[j]) j = m;
else j--;
}
return numbers[i];
}
}
50. 第一个只出现一次的字符
思路
用hashMap存储字符和是否重复出现的标志。
class Solution {
public char firstUniqChar(String s) {
Map<Character, Boolean> strMap = new HashMap<>();
char[] ch = s.toCharArray();
for(char c : ch){
strMap.put(c, !strMap.containsKey(c));
}
for(char c : ch){
if(strMap.get(c)) return c;
}
return ' ';
}
}