行百里者半九十 —— 查找算法(中等)

剑指 Offer 04. 二维数组中的查找
剑指 Offer 11. 旋转数组的最小数字
剑指 Offer 50. 第一个只出现一次的字符

1、二维数组中的查找

在一个 n * m 的二维数组中,每一行都按照从左到右递增的顺序排序,每一列都按照从上到下递增的顺序排序。请完成一个高效的函数,输入这样的一个二维数组和一个整数,判断数组中是否含有该整数。
示例:

现有矩阵 matrix 如下:
[
  [1,   4,  7, 11, 15],
  [2,   5,  8, 12, 19],
  [3,   6,  9, 16, 22],
  [10, 13, 14, 17, 24],
  [18, 21, 23, 26, 30]
]

题解1:暴力破解,依次遍历,不是最优解法
题解2:将矩阵逆时针旋转45度,如下,类似于二叉搜索树,一右上角作为根节点,开始搜索,

 示例代码:

 1 class Solution {
 2 public:
 3     bool findNumberIn2DArray(vector<vector<int>>& matrix, int target) {
 4         int i = matrix.size() - 1, j = 0;
 5         while(i >= 0 && j < matrix[0].size())
 6         {
 7             if(matrix[i][j] > target) i--;
 8             else if(matrix[i][j] < target) j++;
 9             else return true;
10         }
11         return false;
12     }
13 };

2、旋转数组的最小数字

把一个数组最开始的若干个元素搬到数组的末尾,我们称之为数组的旋转。输入一个递增排序的数组的一个旋转,输出旋转数组的最小元素。例如,数组 [3,4,5,1,2] 为 [1,2,3,4,5] 的一个旋转,该数组的最小值为1。

示例 1:

输入:[3,4,5,1,2]
输出:1

示例 2:

输入:[2,2,2,0,1]
输出:0

题解1:暴力破解,直接遍历,[n]>[n+1]时,[n+1]就是最小值;
题解2:二分法,用右边位置和中间位置的元素比较
 1 #include <iostream>
 2 #include <vector>
 3 
 4 using namespace std;
 5 
 6 class Solution {
 7 public:
 8     int minArray(vector<int> &numbers) {
 9         int size = numbers.size();
10         if (size == 0) {
11             return 0;
12         }
13 
14         int left = 0;
15         int right = size - 1;
16 
17         while (left < right) {
18             int mid = left + (right - left) / 2;
19             // int mid = left + ((right - left) >> 1);
20             if (numbers[mid] > numbers[right]) {
21                 // [3, 4, 5, 1, 2],mid 以及 mid 的左边一定不是最小数字
22                 // 下一轮搜索区间是 [mid + 1, right]
23                 left = mid + 1;
24             } else if (numbers[mid] == numbers[right]) {
25                 // 只能把 right 排除掉,下一轮搜索区间是 [left, right - 1]
26                 right--;
27             } else {
28                 // 此时 numbers[mid] < numbers[right]
29                 // mid 的右边一定不是最小数字,mid 有可能是,下一轮搜索区间是 [left, mid]
30                 right = mid;
31             }
32         }
33         return numbers[left];
34     }
35 };

3、第一个只出现一次的字符

在字符串 s 中找出第一个只出现一次的字符。如果没有,返回一个单空格。 s 只包含小写字母。

示例 1:
输入:s = "abaccdeff"
输出:'b'

示例 2:
输入:s = ""
输出:' '

题解:很容易想到哈希表,第一次对字符串遍历时,使用哈希表映射统计出每个字符出现的次数,第二次遍历时,只有遍历到一个只出现一次的字符,就返回它,否则就返回空格。

 1 class Solution {
 2 public:
 3     char firstUniqueChar(string s) {
 4         unorder_map<int, int> frequency;
 5         for(char c: s){
 6             ++frequency[ch];
 7         }
 8         for(int i=0; i < s.size(); ++i){
 9             if(frequency[s[i]] == i)
10                 return s[i];
11         }
12         return ' ';
13     }    
14 };
原文地址:https://www.cnblogs.com/y4247464/p/15580011.html