剑指offer 第5天 查找算法(中等)C++题解

一、二维数组中的查找

剑指 Offer 04. 二维数组中的查找icon-default.png?t=M85Bhttps://leetcode.cn/problems/er-wei-shu-zu-zhong-de-cha-zhao-lcof/

在一个 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]
]

给定 target = 5,返回 true。

给定 target = 20,返回 false。

限制:

0 <= n <= 1000

0 <= m <= 1000

解题思路:

1.暴力解法:顺序查找,时间复杂度O(NM),没有用到每一行都按照从左到右递增的顺序,每一列都按照从上到下递增的顺序的特点,显然还有更高效的时间复杂度算法。

2.由每一行都按照从左到右递增的顺序,每一列都按照从上到下递增的顺序的特点,故从左下角的元素开始,同列元素都小于他,同行元素都大于他,因此可以高效找到目标元素。

2.右上角元素,同列元素都大于他,同行元素都小于他,也可高校找到目标元素。

具体细节:

1.从矩阵左下角元素matrix[i][j] 开始遍历:

2.当 matrix[i][j] > target 时,i-- ;

3.当 matrix[i][j] < target 时,j++;

4.当 matrix[i][j] = target 时,返回 true ,找到目标值。

5.若行索引或列索引越界,则代表矩阵中无目标值,返回 false 。 

复杂度分析:

1.时间复杂度:从左下到右上还没找到的话最坏时间复杂度O(N+M)。

2.空间复杂度:常数级别变量O(1)。

代码实现:

class Solution {
public:
    bool findNumberIn2DArray(vector<vector<int>>& matrix, int target) {
        int n = matrix.size();
        if (n == 0) return false;
        int m = matrix[0].size();
        int i = n - 1;
        int j = 0;
        while (i >= 0 && j < m) {
            if (matrix[i][j] > target) i--;
            else if (matrix[i][j] < target) j++;
            else return true;
        }
        return false;
    }
};

 二、旋转数组的最小数字

剑指 Offer 11. 旋转数组的最小数字icon-default.png?t=M85Bhttps://leetcode.cn/problems/xuan-zhuan-shu-zu-de-zui-xiao-shu-zi-lcof/

把一个数组最开始的若干个元素搬到数组的末尾,我们称之为数组的旋转。

给你一个可能存在 重复 元素值的数组 numbers ,它原来是一个升序排列的数组,并按上述情形进行了一次旋转。请返回旋转数组的最小元素。例如,数组 [3,4,5,1,2] 为 [1,2,3,4,5] 的一次旋转,该数组的最小值为 1。  

注意,数组 [a[0], a[1], a[2], ..., a[n-1]] 旋转一次 的结果为数组 [a[n-1], a[0], a[1], a[2], ..., a[n-2]] 。

示例 1:

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

示例 2:

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

提示:

n == numbers.length
1 <= n <= 5000
-5000 <= numbers[i] <= 5000
numbers 原来是一个升序排序的数组,并进行了 1 至 n 次旋转

解题思路:

1.暴力解法:遍历数组时间复杂度为O(N),并未用到数组升序排列的特点,显然有更优的时间复杂度。

2.二分查找:数组可以分为两个升序数组,左数组元素都大于右数组元素。故最小元素即为右升序数组的第一个元素。

具体细节:

1.初始化left = 0,right = n - 1;

2.循环二分: 计算 mid = (left + right) / 2;

3.当 nums[mid] > nums[right] 时: mid 一定在左排序数组中,left = mid +1;

4.当 nums[mid] < nums[right] 时: mid 一定在右排序数组中,right = mid;

5.当 nums[mid] = nums[right] 时: 无法判断 mid 在哪个排序数组中,right = right - 1 缩小判断范围。

6.返回值: 当 left >= right 时跳出循环,返回右数组的第一个元素nums[left]。

复杂度分析:

1.时间复杂度:二分查找O(logN)。

2.空间复杂度:O(1)。

代码实现:

class Solution {
public:
    int minArray(vector<int>& numbers) {
        int left = 0, right = numbers.size() - 1;
        while (left < right) {
            int mid = (left + right) / 2;
            if (numbers[mid] > numbers[right]) left = mid + 1;
            else if (numbers[mid] < numbers[right]) right = mid;
            else right = right - 1;
        }
        return numbers[left];
    }
};

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

剑指 Offer 50. 第一个只出现一次的字符icon-default.png?t=M85Bhttps://leetcode.cn/problems/di-yi-ge-zhi-chu-xian-yi-ci-de-zi-fu-lcof/

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

示例 1:

输入:s = "abaccdeff"
输出:'b'

示例 2:

输入:s = "" 
输出:' '

限制:

0 <= s 的长度 <= 50000

解题思路:

1.暴力解法:i从0 ~ n - 1遍历字符串,j从i + 1 ~ n - 1遍历字符串,若i都不等于j的话则返回,时间复杂度O(N^2),没有用到字符串只包含小写字母这一特点,仍有更优解。

2.哈希表:使用数组代替哈希表将字符串映射到数组中,数组值大于1则返回字符,没有则返回空格。

具体细节:

1.初始化一个大小为26的数组map[26]用作映射字符串。

2.遍历字符串将其映射到数组map中:map[s[i] - 'a'] ++;

3.再遍历一遍找到第一个只出现一次的字母。

复杂度分析:

1.时间复杂度:遍历两遍字符串,O(N)。

2.空间复杂度:常数级别的数组,O(1)。

代码实现:

class Solution {
public:
    char firstUniqChar(string s) {
        int map[26] = {0};
        for (int i = 0; i < s.size(); i++) {
            map[s[i] - 'a'] ++;
        }
        for (int i = 0; i < s.size(); i++) {
            if (map[s[i] - 'a'] == 1) return s[i]; 
        }
        return ' ';
    }
};

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

杨小木木

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值