查找算法-题型讲解

简介: 查找算法-题型讲解

励志

题目来源:
https://leetcode-cn.com/leetbook/detail/illustration-of-algorithm/

在这里插入图片描述
配合学习文档:
https://www.kancloud.cn/alex_wsc/dataalg/1853982

书籍推荐:

《漫画算法》
在这里插入图片描述
视频推荐:
https://www.bilibili.com/video/BV1E4411H73v

目录

在这里插入图片描述

一、剑指 Offer 03. 数组中重复的数字

题:

找出数组中重复的数字。

在一个长度为 n 的数组 nums 里的所有数字都在 0~n-1 的范围内。数组中某些数字是重复的,但不知道有几个数字重复了,也不知道每个数字重复了几次。请找出数组中任意一个重复的数字。

示例 1:

输入:
[2, 3, 1, 0, 2, 5, 3]
输出:2 或 3 

限制:

2 <= n <= 100000

解:

解题思路:哈希表
AC代码:

class Solution {
    public int findRepeatNumber(int[] nums) {
        Set<Integer> dic = new HashSet<>();
        for(int num : nums){
            if(dic.contains(num)) return num;
            dic.add(num);
        }
        return -1;
    }
}
  • 时间复杂度 O(N) : 遍历数组使用 O(N),HashSet 添加与查找元素皆为 O(1)
  • 空间复杂度 O(N) : HashSet 占用 O(N) 大小的额外空间

解题思路:索引映射(数组元素的索引和值是一对多的关系)
在这里插入图片描述
在这里插入图片描述

AC代码:

class Solution {
    public int findRepeatNumber(int[] nums) {
        int index = 0; // 指针
        int len = nums.length;
        while(index < len){
            if(nums[index] == index){ // 索引一一对应
                index++;
                continue;
            }
            if(nums[nums[index]] == nums[index]) return nums[index];
            // 交换
            int temp = nums[index];
            nums[index] = nums[temp];
            nums[temp] = temp;
        }
        return -1;
    }
}

时间复杂度 O(N) : 遍历数组使用 O(N) ,每轮遍历的判断和交换操作使用 O(1)。
空间复杂度 O(1) : 使用常数复杂度的额外空间。

二、剑指 Offer 04. 二维数组中的查找

题:

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

解:

解题思路:消消乐
在这里插入图片描述
小了往上走,大了往右走。
AC代码:

class Solution {
    public boolean findNumberIn2DArray(int[][] matrix, int target) {
        int i = matrix.length - 1, j = 0; // mark坐标
        while(i >= 0 && j < matrix[0].length){
            if(target < matrix[i][j]) i--; // target小,往上移
            else if(target > matrix[i][j]) j++; // target大,往右移
            else return true;
        }
        return false;
    }
}
  • 时间复杂度 O(M+N):其中,N 和 M 分别为矩阵行数和列数,此算法最多循环 M+N 次。
  • 空间复杂度 O(1): i, j 指针使用常数大小额外空间。

# 三、剑指 Offer 11. 旋转数组的最小数字
## 题:
把一个数组最开始的若干个元素搬到数组的末尾,我们称之为数组的旋转。输入一个递增排序的数组的一个旋转,输出旋转数组的最小元素。例如,数组 [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

## 解:
解题思路:二分法(排序数组的查找问题首先考虑使用 二分法 解决,其可将 遍历法线性级别 时间复杂度降低至 对数级别 。)
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

AC代码:

class Solution {
   public int minArray(int[] numbers) {
       int len = numbers.length;
       int i = 0, j = len - 1; // 左右指针
       while(i < j){
           int mid = (i + j) / 2;
           if(numbers[mid] < numbers[j]) j = mid;
           else if(numbers[mid] > numbers[j]) i = mid + 1; // mid一定不是最小值,越过
           else j--; // 缩小二分范围
       }
       return numbers[i];
   }
}

补充:
在这里插入图片描述
在这里插入图片描述

四、剑指 Offer 50. 第一个只出现一次的字符

题:

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

示例:

s = "abaccdeff"
返回 "b"

s = "" 
返回 " "

限制:

0 <= s 的长度 <= 50000

解:

解题思路:哈希表
AC代码:

class Solution {
    public char firstUniqChar(String s) {
        Map<Character, Boolean> dic = new HashMap<>();
        char[] sc = s.toCharArray();
        for(char c : sc){
            dic.put(c,!dic.containsKey(c));
        }
        for(char c : sc){
            if(dic.get(c)) return c;
        }
        return ' ';
    }
}
  • 时间复杂度 O(N): N 为字符串 s 的长度;需遍历 s 两轮,使用 O(N) ;HashMap 查找操作的复杂度为 O(1) ;
  • 空间复杂度 O(1) : 由于题目指出 s 只包含小写字母,因此最多有 26 个不同字符,HashMap 存储需占用 O(26) = O(1)的额外空间。

解题思路:有序哈希表(缩小了第二次遍历的范围)
AC代码:

class Solution {
    public char firstUniqChar(String s) {
        Map<Character, Boolean> dic = new LinkedHashMap<>();
        char[] sc = s.toCharArray();
        for(char c : sc)
            dic.put(c, !dic.containsKey(c));
         //  大同小异
        for(Map.Entry<Character, Boolean> d : dic.entrySet()){
           if(d.getValue()) return d.getKey();
        }
        return ' ';
    }
}

五、剑指 Offer 53 - I. 在排序数组中查找数字 I

题:

统计一个数字在排序数组中出现的次数。

示例 1:

输入: nums = [5,7,7,8,8,10], target = 8
输出: 2

示例 2:

输入: nums = [5,7,7,8,8,10], target = 6
输出: 0

提示:

0 <= nums.length <= 105
-109 <= nums[i] <= 109
nums 是一个非递减数组
-109 <= target <= 109

解:

解题思路:二分法
在这里插入图片描述

AC代码:

class Solution {
    public int search(int[] nums, int target) {
        // 搜索右边界 right
        int i = 0, j = nums.length - 1;
        while(i <= j) {
            int m = (i + j) / 2;
            // 卡左(等号)指针位置
            if(nums[m] <= target) i = m + 1;
            else j = m - 1;
        }
        int right = i;
        // 若数组中无 target ,则提前返回
        if(j >= 0 && nums[j] != target) return 0;
        // 搜索左边界 left
        i = 0; j = nums.length - 1;
        while(i <= j) {
            int m = (i + j) / 2;
            // 卡右(等号)指针位置
            if(nums[m] >= target) j = m - 1;
            else i = m + 1;
        }
        int left = j;
        return right - left - 1;
    }
}

代码有点冗余,优化优化(数组 nums 中元素都为整数):
在这里插入图片描述
通俗的讲就是 (tar - 1卡右) 等于 (tar 卡左 + 1),把卡右提取一个方法,减少冗余

AC代码:

class Solution {
    public int search(int[] nums, int target) {
        return findRight(nums, target) - findRight(nums, target - 1);
    }
    int findRight(int[] nums, int tar){
        int i = 0, j = nums.length - 1;
        while(i <= j){
            int m = (i + j) / 2; // 下取整
            // 卡左(限制i),取右(tar在右),舍边(i=m无效)
            if(nums[m] <= tar) i = m + 1;
            else j = m - 1;
        }
        return i;
    }
}

六、剑指 Offer 53 - II. 0~n-1 中缺失的数字

题:

一个长度为n-1的递增排序数组中的所有数字都是唯一的,并且每个数字都在范围0~n-1之内。在范围0~n-1内的n个数字中有且只有一个数字不在该数组中,请找出这个数字。

示例 1:

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

示例 2:

输入: [0,1,2,3,4,5,6,7,9]
输出: 8

限制:

1 <= 数组长度 <= 10000

解:

解题思路:二分法
AC代码:

class Solution {
    public int missingNumber(int[] nums) {
        int i = 0, j = nums.length - 1;
        while(i <= j){
            int m = (i + j) / 2;
            // 卡i,去边,取右
            if(nums[m] == m) i = m + 1;
            else j = m - 1;
        }
        return i;
    }
}
相关文章
|
6月前
|
算法
【数据结构与算法】单链表反转、双链表反转(含相关题型)
【数据结构与算法】单链表反转、双链表反转(含相关题型)
61 0
|
算法
蓝桥杯算法竞赛第一周题型总结
蓝桥杯算法竞赛第一周题型总结
76 0
|
5月前
|
算法
基础算法-去重字符串,辗转相除法,非递归前序遍历二叉树题型分析
基础算法-去重字符串,辗转相除法,非递归前序遍历二叉树题型分析
|
算法
算法 - 蓝桥杯并查集题型
算法 - 蓝桥杯并查集题型
|
机器学习/深度学习 人工智能 算法
蓝桥杯最后一天复习?各大算法四步法教你轻松秒杀各种题型
大家好,我是泡泡,距离蓝桥杯还有一天时间,我们一定要把握住最后的时间,跟着我,把全部的题型复习整理一遍,让自己不再迷茫不自信,AK蓝桥!
237 0
蓝桥杯最后一天复习?各大算法四步法教你轻松秒杀各种题型
|
机器学习/深度学习 算法
回溯算法-题型归纳总结
回溯算法-题型归纳总结
100 0
回溯算法-题型归纳总结
|
监控 算法
贪心算法-题型讲解
贪心算法-题型讲解
149 0
贪心算法-题型讲解
|
移动开发 算法 测试技术
二分查找算法 四种题型六道题目总结,从此二分不迷路!
二分查找算法 四种题型六道题目总结,从此二分不迷路!
159 0
|
算法 前端开发 测试技术
|
1月前
|
算法 安全 数据安全/隐私保护
基于game-based算法的动态频谱访问matlab仿真
本算法展示了在认知无线电网络中,通过游戏理论优化动态频谱访问,提高频谱利用率和物理层安全性。程序运行效果包括负载因子、传输功率、信噪比对用户效用和保密率的影响分析。软件版本:Matlab 2022a。完整代码包含详细中文注释和操作视频。
下一篇
无影云桌面