• 《剑指Offer》搜索算法题篇——更易理解的思路~


    本篇若要说难点,就是时间复杂度的把控,还有什么样的解法容易让大家看懂理解


    JZ53 数字在升序数组中出现的次数

    描述

    给定一个长度为 n 的非降序数组和一个非负数整数 k ,要求统计 k 在数组中出现的次数

    数据范围:0 \le n \le 1000 , 0 \le k \le 1000≤n≤1000,0≤k≤100,数组中每个元素的值满足 0 \le val \le 1000≤val≤100
    要求:空间复杂度 O(1),时间复杂度 O(logn)

    思路(二分法):由于所需时间复杂度为O(logn),所以可以先通过二分法找到所给的k值,并拿到k值的下标,因为是有序数组,所以由此展开——用left和right分别向左和向右遍历,若与k值相等,则给计数器+1,最后返回计数器即可;

    1. //计数器
    2. private int count = 0;
    3. public int GetNumberOfK(int [] array , int k) {
    4. //由于时间复杂度为O(logn),所以要利用二分查找先找到这个数
    5. int len = array.length;
    6. int left = 0;
    7. int right = len - 1;
    8. int keyIndex = binarySearch(array, left, right, k);
    9. if(count == -1){
    10. return 0;
    11. }
    12. //因为有序,所以分别向两边扩展找相同的元素,找到了,计数就加1
    13. //左扩展
    14. left = keyIndex - 1;
    15. while(left >= 0 && array[left] == k){
    16. count++;
    17. left--;
    18. }
    19. //右扩展
    20. right = keyIndex + 1;
    21. while(right < len && array[right] == k){
    22. count++;
    23. right++;
    24. }
    25. return count;
    26. }
    27. //二分查找
    28. private int binarySearch(int[] array, int left, int right, int k){
    29. while(left <= right){
    30. int mid = (left + right) / 2;
    31. if(k < array[mid]){
    32. right = mid - 1;
    33. }else if(array[mid] < k){
    34. left = mid + 1;
    35. }else{
    36. count++;
    37. return mid;
    38. }
    39. }
    40. return -1;
    41. }

    JZ4 二维数组中的查找

    描述

    在一个二维数组array中(每个一维数组的长度相同),每一行都按照从左到右递增的顺序排序,每一列都按照从上到下递增的顺序排序。请完成一个函数,输入这样的一个二维数组和一个整数,判断数组中是否含有该整数。

    [

    [1,2,8,9],
    [2,4,9,12],
    [4,7,10,13],
    [6,8,11,15]

    ]

    给定 target = 7,返回 true。

    给定 target = 3,返回 false。

    数据范围:矩阵的长宽满足 0 \le n,m \le 5000≤n,m≤500 , 矩阵中的值满足 0 \le val \le 10^90≤val≤109
    进阶:空间复杂度 O(1),时间复杂度 O(n+m)

    思路(这题其实非常简单,但此题的标出的难度却是中等,通过率只有百分之二十几?想必大多数人都是因为时间复杂度超过了O(n + m)):为什么简单?二维数组,对每一行进行二分查找就ok~

    1. public boolean Find(int target, int [][] array) {
    2. //每一行进行二分查找
    3. for(int i = 0; i < array.length; i++){
    4. boolean flay = binarySearch(target, array[i]);
    5. if(flay){
    6. return true;
    7. }
    8. }
    9. return false;
    10. }
    11. public boolean binarySearch(int target, int[] array){
    12. int left = 0;
    13. int right = array.length - 1;
    14. while(left <= right){
    15. int mid = (left + right) / 2;
    16. if(target < array[mid]){
    17. right = mid - 1;
    18. }else if(target > array[mid]){
    19. left = mid + 1;
    20. }else{
    21. return true;
    22. }
    23. }
    24. return false;
    25. }

    JZ11 旋转数组的最小数字

    描述

    有一个长度为 n 的非降序数组,比如[1,2,3,4,5],将它进行旋转,即把一个数组最开始的若干个元素搬到数组的末尾,变成一个旋转数组,比如变成了[3,4,5,1,2],或者[4,5,1,2,3]这样的。请问,给定这样一个旋转数组,求数组中的最小值。

    数据范围:1 \le n \le 100001≤n≤10000,数组中任意元素的值: 0 \le val \le 100000≤val≤10000

    要求:空间复杂度:O(1) ,时间复杂度:O(logn)

    思路(二分法):因为数组为非降序数组,所以可以通过二分法,进行循环即可,但要注意以下情况:当mid指向元素大于right指向元素时,说明目标值一定在mid指向的右边;当mid指向元素小于right指向元素时,说明一定在mid指向的左边;若mid指向元素等于right指向元素时,不确定,可以用right缩小范围继续比较;

    1. public int minNumberInRotateArray(int [] array) {
    2. int left = 0;
    3. int right = array.length - 1;
    4. while(left < right){
    5. int mid = (left + right) / 2;
    6. //若中间值大于最右边,说明目标在中间值右边
    7. if(array[mid] > array[right]){
    8. left = mid + 1;
    9. }
    10. //此时不确定,比如 1 1 1 0 1,所以继续缩小范围
    11. else if(array[mid] == array[right]){
    12. right--;
    13. }
    14. //不在右边就在左边
    15. else{
    16. right = mid;
    17. }
    18. }
    19. return array[left];
    20. }

     

  • 相关阅读:
    LinEnum提权辅助脚本使用指南
    Socket网络编程(三)——TCP快速入门
    SkyWalking 告警规则配置说明
    【MySQL基本查询(下)】
    c#与汇川plc通信 使用官网API库
    ES6 入门教程 10 对象的扩展 10.7 AggregateError 错误对象 & 10.8 Error 对象的 cause 属性
    同花顺_代码解析_技术指标_Z_3
    Springboot 集成 MongoDB
    2022年湖北大学招生简章--成人高等教育高起专、专升本学历提升
    操作系统备考学习 day6(2.3.2 - 2.3.4)
  • 原文地址:https://blog.csdn.net/CYK_byte/article/details/126453500