• 数字在排序数组中出现的次数


    ##题目描述 统计一个数字在排序数组中出现的次数。

    思路

    二分查找:

    1. 利用二分查找找到一个符合条件的值,然后循环搜索这个值前后重复的次数。(循环搜索使得算法一部分退化到O(m))。
      时间复杂度O(m+lgn),空间复杂度O(1)。

    2. 使用两个修改判定的二分查找,分别找到数字第一次出现和最后一次出现的位置。(推荐)
      时间复杂度O(lgn),空间复杂度O(1)。

    3. 由于题目数组的特殊性(int),可以分别对搜索值±0.5,然后使用二分查找搜索两个值。(特殊)
      时间复杂度O(lgn),空间复杂度O(1)。

    代码1

    public class Solution {
        public int GetNumberOfK(int [] array , int k) {
            if(array == null || array.length == 0)    return 0;
            int cnt = 0;
            int low = 0;
            int mid = 0;
            int high = array.length - 1;
            while(low <= high) {
                mid = (low + high) / 2;
                if(array[mid] == k) {
                    break;
                } else if(array[mid] < k) {
                    low = mid + 1;
                } else {
                    high = mid - 1;
                }
            }
            for(int i = mid - 1; i >= 0; i--) {
                if(array[i] == k) {
                    cnt++;
                } else {
                    break;
                }
            }
            for(int i = mid; i < array.length; i++) {
                if(array[i] == k) {
                    cnt++;
                } else {
                    break;
                }
            }
            return cnt;
        }
    }
    

    代码2

    public class Solution {
        private int biSearchfirst(int[] arr, int k, int low, int high, int mid) {
            while(low <= high) {
                mid = (low + high) / 2;
                if(arr[mid] == k) {
                    if(mid == 0 ||  arr[mid-1]!=k) {
                        return mid;
                    } else {
                        high = mid - 1;
                    }
                } else if(arr[mid] < k) {
                    low = mid + 1;
                } else {
                    high = mid - 1;
                }
            }
            return -1;
        }
        
        private int biSearchlast(int[] arr, int k, int low, int high, int mid) {
            while(low <= high) {
                mid = (low + high) / 2;
                if(arr[mid] == k) {
                    if(mid == arr.length - 1 ||  arr[mid+1]!=k) {
                        return mid;
                    } else {
                        low = mid + 1;
                    }
                } else if(arr[mid] < k) {
                    low = mid + 1;
                } else {
                    high = mid - 1;
                }
            }
            return -1;
        }
        
        public int GetNumberOfK(int [] array , int k) {
            if(array == null || array.length == 0)    return 0;
            int first = biSearchfirst(array, k, 0, array.length - 1, 0);
            int last = biSearchlast(array, k, 0, array.length - 1, 0);
            if(first == -1 || last == -1)    return 0;
            return last - first + 1;
        }
    }
    

    代码3

    public class Solution {
        private int biSearch(int[] arr, double k) {
            int low = 0;
            int mid = 0;
            int high = arr.length - 1;
            while(low <= high) {
                mid = (low + high) / 2;
                if(arr[mid] < k) {
                    low = mid + 1;
                } else {
                    high = mid -1;
                }
            }
            return low;
        }
        public int GetNumberOfK(int [] array , int k) {
            if(array == null || array.length == 0)    return 0;
            int left = biSearch(array, k - 0.5);
            int right = biSearch(array, k + 0.5);
            return right - left;
        }
    }
    

    笔记

    二叉查找,while(low <= high),若k存在:

    • 此时搜索k-ε的值,无论是否存在,mid返回的都是k的前一位,low返回的是k,high返回的是mid。
    • 此时搜索k+ε的值,无论是否存在,mid返回的都是k的后一位,high返回的是k,low返回的是mid。
    • 所以代码3里right-left实际上就是low2-low1 = k最后一次出现的后一位 - k第一次出现的位置。

    若k不存在:k最后一次出现的后一位 等于 k第一次出现的位置,相当于插进来一个数。
    所以二分法使用第三种代码方法时,只需要用low或者high代替mid返回就行,最后位置的逼近自然会完成。

    总结,二分法搜索若存在,返回mid,若不存在,则返回low或者high(类比向上向下取整,同时取一个方向的选择)。

    二分法与分治法的问题都可以先写出基本框架,再通过修改判定或添加操作解决问题。

  • 相关阅读:
    Spring Boot 配置文件和命令行配置
    Spring Boot RestApi 测试教程 Mock 的使用
    Spring Boot 集成 Swagger2 教程
    Spring Boot Web 开发@Controller @RestController 使用教程
    SpringBoot RESTful API 架构风格实践
    Spring Boot 使用 Aop 实现日志全局拦截
    Spring Boot 全局异常处理
    Spring Boot Thymeleaf 模板引擎的使用
    Spring Boot Log 日志使用教程
    IDEA 下的 github 创建提交与修改
  • 原文地址:https://www.cnblogs.com/ustca/p/12361807.html
Copyright © 2020-2023  润新知