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

人生之路不会是一帆风顺的,我们会遇上顺境,也会遇上逆境,在所有成功路上折磨你的,背后都隐藏着激励你奋发向上的动机,人生没有如果,只有后果与结果,成熟,就是用微笑来面对一切小事。

导读:本篇文章讲解 《剑指Offer》搜索算法题篇——更易理解的思路~,希望对大家有帮助,欢迎收藏,转发!站点地址:www.bmabk.com,来源:原文

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


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,最后返回计数器即可;

    //计数器
    private int count = 0;
    public int GetNumberOfK(int [] array , int k) {
        //由于时间复杂度为O(logn),所以要利用二分查找先找到这个数
        int len = array.length;
        int left = 0;
        int right = len - 1;
        int keyIndex = binarySearch(array, left, right, k);
        if(count == -1){
            return 0;
        }
        //因为有序,所以分别向两边扩展找相同的元素,找到了,计数就加1
        //左扩展
        left = keyIndex - 1;
        while(left >= 0 && array[left] == k){
            count++;
            left--;
        }
        //右扩展
        right = keyIndex + 1;
        while(right < len && array[right] == k){
            count++;
            right++;
        }
        return count;
    }
    //二分查找
    private int binarySearch(int[] array, int left, int right, int k){
        while(left <= right){
            int mid = (left + right) / 2;
            if(k < array[mid]){
                right = mid - 1;
            }else if(array[mid] < k){
                left = mid + 1;
            }else{
                count++;
                return mid;
            }
        }
        return -1;
    }

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~

    public boolean Find(int target, int [][] array) {
        //每一行进行二分查找
        for(int i = 0; i < array.length; i++){
            boolean flay = binarySearch(target, array[i]);
            if(flay){
                return true;
            }
        }
        return false;
    }
    public boolean binarySearch(int target, int[] array){
        int left = 0;
        int right = array.length - 1;
        while(left <= right){
            int mid = (left + right) / 2;
            if(target < array[mid]){
                right = mid - 1;
            }else if(target > array[mid]){
                left = mid + 1;
            }else{
                return true;
            }
        }
        return false;
    }

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缩小范围继续比较;

    public int minNumberInRotateArray(int [] array) {
        int left = 0;
        int right = array.length - 1;
        while(left < right){
            int mid = (left + right) / 2;
            //若中间值大于最右边,说明目标在中间值右边
            if(array[mid] > array[right]){
                left = mid + 1;
            }
            //此时不确定,比如 1 1 1 0 1,所以继续缩小范围
            else if(array[mid] == array[right]){
                right--;
            }
            //不在右边就在左边
            else{
                right = mid;
            }
        }
        return array[left];
    }

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

 

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

文章由半码博客整理,本文链接:https://www.bmabk.com/index.php/post/124338.html

(0)
飞熊的头像飞熊bm

相关推荐

发表回复

登录后才能评论
半码博客——专业性很强的中文编程技术网站,欢迎收藏到浏览器,订阅我们!