【算法训练-数组 五】【二分查找】:旋转排序数组的最小数字、旋转排序数组的指定数字

这篇具有很好参考价值的文章主要介绍了【算法训练-数组 五】【二分查找】:旋转排序数组的最小数字、旋转排序数组的指定数字。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

废话不多说,喊一句号子鼓励自己:程序员永不失业,程序员走向架构!本篇Blog的主题是【数组的二分查找】,使用【数组】这个基本的数据结构来实现,这个高频题的站点是:CodeTop,筛选条件为:目标公司+最近一年+出现频率排序,由高到低的去牛客TOP101去找,只有两个地方都出现过才做这道题(CodeTop本身汇聚了LeetCode的来源),确保刷的题都是高频要面试考的题。

【算法训练-数组 五】【二分查找】:旋转排序数组的最小数字、旋转排序数组的指定数字,# 数组,算法

名曲目标题后,附上题目链接,后期可以依据解题思路反复快速练习,题目按照题干的基本数据结构分类,且每个分类的第一篇必定是对基础数据结构的介绍

旋转排序数组的最小数字【MID】

先来找最小值

题干

直接粘题干和用例
【算法训练-数组 五】【二分查找】:旋转排序数组的最小数字、旋转排序数组的指定数字,# 数组,算法

解题思路

通过题目描述我们知道,旋转点后的排序子区间最大值也比旋转点之前的排序子区间最小值小,最小值就是旋转点,也就是数组的中间部分,所以我们使用碰撞双指针从两边向中心搜索,不断缩小搜索范围:

  • step 1:双指针指向旋转后数组的首尾,作为区间端点。
  • step 2:若是区间中点值大于区间右界值,说明中点在左侧递增区间,则最小的数字一定在中点右边
  • step 3:若是区间中点值等于区间右界值,则是不容易分辨最小数字在哪半个区间,比如[1,1,1,0,1],应该逐个缩减右界
  • step 4:若是区间中点值小于区间右界值,说明中点在右侧递增区间,则最小的数字一定在中点左边
  • step 5:通过调整区间最后即可锁定最小值所在。

代码实现

给出代码实现基本档案

基本数据结构数组
辅助数据结构
算法二分查找
技巧双指针(碰撞双指针)

其中数据结构、算法和技巧分别来自:

  • 10 个数据结构:数组、链表、栈、队列、散列表、二叉树、堆、跳表、图、Trie 树
  • 10 个算法:递归、排序、二分查找、搜索、哈希算法、贪心算法、分治算法、回溯算法、动态规划、字符串匹配算法
  • 技巧:双指针、滑动窗口、中心扩散

当然包括但不限于以上

import java.util.*;


public class Solution {
    /**
     * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
     *
     *
     * @param nums int整型一维数组
     * @return int整型
     */
    public int minNumberInRotateArray (int[] nums) {
        // 1 入参判断,参数有效性校验
        if (nums == null || nums.length == 0) {
            return -1;
        }

        // 2 定义左右碰撞指针,找中点位置
        int left = 0;
        int right = nums.length - 1;
        while (left <= right) {
            int mid = (left + right) / 2;
            if (nums[mid] > nums[right]) {
                // mid在左侧递增区间,最小值在mid右侧[mid+1,right]
                left = mid + 1;

            } else if (nums[mid] < nums[right]) {
                // mid在右侧递增区间,最小值为mid或mid左侧[left,mid]
                right = mid;
            } else {
                // 无法判断,缩小右边界
                right--;
            }
        }

        return nums[left];
    }
}

复杂度分析

时间复杂度:O(log n),二分法最坏情况对n取2的对数
空间复杂度:O(1),常数级变量,无额外辅助空间

搜索旋转排序数组【MID】

OK,接下来难度升级,不找最小值,找的是指定值

题干

直接粘题干和用例
【算法训练-数组 五】【二分查找】:旋转排序数组的最小数字、旋转排序数组的指定数字,# 数组,算法

解题思路

给出解题思路,最好有图对于有序数组,可以使用二分查找的方法查找元素。但是这道题中,数组本身不是有序的,进行旋转后只保证了数组的局部是有序的,这还能进行二分查找吗?答案是可以的。

可以发现的是,我们将数组从中间分开成左右两部分的时候,一定有一部分的数组是有序的。拿示例来看,我们从 6 这个位置分开以后数组变成了 [4, 5, 6] 和 [7, 0, 1, 2] 两个部分,其中左边 [4, 5, 6] 这个部分的数组是有序的,其他也是如此。

这启示我们可以在常规二分查找的时候查看当前 mid 为分割位置分割出来的两个部分 [l, mid] 和 [mid + 1, r] 哪个部分是有序的,并根据有序的那个部分确定我们该如何改变二分查找的上下界,因为我们能够根据有序的那部分判断出 target 在不在这个部分:

  • 如果 [l, mid - 1] 是有序数组,且 target 的大小满足 [nums[l],nums[mid]),则我们应该将搜索范围缩小至 [l, mid - 1],否则在 [mid + 1, r] 中寻找。
  • 如果 [mid, r] 是有序数组,且 target 的大小满足 (nums[mid+1],nums[r]],则我们应该将搜索范围缩小至 [mid + 1, r],否则在 [l, mid - 1] 中寻找。

【算法训练-数组 五】【二分查找】:旋转排序数组的最小数字、旋转排序数组的指定数字,# 数组,算法

  • 定理一:只有在顺序区间内才可以通过区间两端的数值判断target是否在其中
  • 定理二:判断顺序区间还是乱序区间,只需要对比 left 和 right 是否是顺序对即可,left <= right,顺序区间,否则乱序区间。
  • 定理三:每次二分都会至少存在一个顺序区间

通过不断的用Mid二分,根据定理二,将整个数组划分成顺序区间和乱序区间,然后利用定理一判断target是否在顺序区间,如果在顺序区间,下次循环就直接取顺序区间,如果不在,那么下次循环就取乱序区间。最终target一定会在一个顺序区间,即使只有它一个元素

代码实现

给出代码实现基本档案

基本数据结构数组
辅助数据结构
算法二分查找
技巧双指针(碰撞双指针)

其中数据结构、算法和技巧分别来自:

  • 10 个数据结构:数组、链表、栈、队列、散列表、二叉树、堆、跳表、图、Trie 树
  • 10 个算法:递归、排序、二分查找、搜索、哈希算法、贪心算法、分治算法、回溯算法、动态规划、字符串匹配算法
  • 技巧:双指针、滑动窗口、中心扩散

当然包括但不限于以上

class Solution {
    public int search(int[] nums, int target) {
       // 1 入参校验
        if (nums == null || nums.length == 0) {
            return -1;
        }

        // 2 定义双指针
        int left = 0;
        int right = nums.length - 1;
        while (left <= right) {
            int mid = (left + right) / 2;
            if (nums[mid] == target) {
                return mid;
            }
            // 因为只有在有序区间内target的判断才有意义,所以每次都在有序区间内判断,并且依据目标值是否在有序区间内,移动左右指针
            if (nums[left] <= nums[mid]) {
                // 如果左边是顺序区间
                if (target >= nums[left] && target < nums[mid]) {
                    // 如果目标值在顺序区间,在顺序区间搜寻[left,mid-1]
                    right = mid - 1;
                } else {
                    // 如果目标值不在顺序区间,在非顺序区间搜寻[mid+1,right]
                    left = mid + 1;
                }
            } else {
                // 如果右边是顺序区间
                if (target > nums[mid] && target <= nums[right]) {
                    // 如果目标值在顺序区间,在顺序区间搜寻[mid+1,right]
                    left = mid + 1;
                } else {
                    // 如果目标值不在顺序区间,在非顺序区间搜寻[left,mid-1]
                    right = mid - 1;
                }
            }
        }
        return -1;
    }
}

复杂度分析

时间复杂度:O(log n),二分法最坏情况对n取2的对数
空间复杂度:O(1),常数级变量,无额外辅助空间文章来源地址https://www.toymoban.com/news/detail-708424.html

到了这里,关于【算法训练-数组 五】【二分查找】:旋转排序数组的最小数字、旋转排序数组的指定数字的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 每天一道leetcode:剑指 Offer 53 - I. 在排序数组中查找数字 I(适合初学者&二分查找)

    统计一个数字在排序数组中出现的次数。 0 = nums.length = 10^5 -10^9 = nums[i] = 10^9 nums 是一个非递减数组 -10^9 = target = 10^9 使用两次二分查找找到target在数组中的左右边界,然后长度就是右边界减去左边界再加一,最后返回长度即可。   欢迎大家在评论区讨论,如有不懂的代码部分

    2024年02月14日
    浏览(42)
  • 33. 搜索旋转排序数组(二分法)

    题目要求必须设计一个时间复杂度为  O(log n)  的算法解决此问题,所以我们可以采用二分法。 Step1. 先把 nums[0] 作为目标值,通过二分法找到旋转点索引; Step2. 如果旋转点索引为0,则数组本身就是升序的,否则思想上可以将数组一分为二,看做两个升序数组。 Step3. 判断

    2024年02月05日
    浏览(31)
  • Java---第四章(数组基础,冒泡排序,二分查找,多维数组)

    概念: 数组是编程语言中的一种常见的数据结构,能够存储一组相同类型的数据 作用: 存储一组相同类型的数据,方便进行数理统计(求最大值,最小值,平均值以及总和),也可以进行信息的展示 定义: 第一种: 只能在定义数组同时赋值时使用 第二种: 可以在定义数组

    2024年02月09日
    浏览(37)
  • 34. 在排序数组中查找元素的第一个和最后一个位置(二分查找)

    二分查找到目标值然后左右找到坐标 问题在于:找左右坐标的时候时间复杂度不是 O(logN) 之前提到过二分查找不仅可找到相等的数值,更关键的是 它可以将数组分为截然不同的两种情况 ,因此我们可以借助这个性质找到 第一个大于等于 target 的值(左下标) 和 第一个大于

    2024年01月22日
    浏览(37)
  • 二分查找:34. 在排序数组中查找元素的第一个和最后一个位置

    个人主页 : 个人主页 个人专栏 : 《数据结构》 《C语言》《C++》《算法》 本篇文章仅是作为小白的我的一些理解,,如果有错误的地方,希望大佬们指出。 题目链接: 34. 在排序数组中查找元素的第一个和最后一个位置 本题数组元素不唯一,可能存在多个target,我们就是

    2024年02月08日
    浏览(37)
  • 【剑指 offer】旋转数组的最小数字

    ✨个人主页:bit me👇 ✨当前专栏:算法训练营👇 核心考点:数组理解,二分查找,临界条件 描述: 有一个长度为 n 的非降序数组,比如[1,2,3,4,5],将它进行旋转,即把一个数组最开始的若干个元素搬到数组的末尾,变成一个旋转数组,比如变成了[3,4,5,1,2],或者[4,5,1,2,3]这

    2023年04月20日
    浏览(43)
  • 二分查找实例1(在排序数组中查找元素的第一个和最后一个位置)

    给你一个按照非递减顺序排列的整数数组  nums ,和一个目标值  target 。请你找出给定目标值在数组中的开始位置和结束位置。 如果数组中不存在目标值  target ,返回  [-1, -1] 。 你必须设计并实现时间复杂度为  O(log n)  的算法解决此问题。 示例 1: 示例 2: 示例 3: 提示

    2024年02月09日
    浏览(32)
  • HOT67-寻找旋转排序数组中的最小值

            leetcode原题链接 :寻找旋转排序数组中的最小值         上一篇 :HOT66-搜索旋转排序数组         下一篇: HOT68-寻找两个正序数组的中位数        已知一个长度为  n  的数组,预先按照升序排列,经由  1  到  n  次  旋转  后,得到输入数组。例如,原数组

    2024年02月16日
    浏览(37)
  • 154. 寻找旋转排序数组中的最小值 II

    已知一个长度为  n  的数组,预先按照升序排列,经由  1  到  n  次  旋转  后,得到输入数组。例如,原数组  nums = [0,1,4,4,5,6,7]  在变化后可能得到: 若旋转  4  次,则可以得到  [4,5,6,7,0,1,4] 若旋转  7  次,则可以得到  [0,1,4,4,5,6,7] 注意,数组  [a[0], a[1], a[2], ...,

    2024年02月15日
    浏览(25)
  • C 语言每日一题——旋转数组的最小数字

     一、题目内容  提供一下该OJ题的链接:旋转数组的最小数字_牛客题霸_牛客网 (nowcoder.com) 二、题目分析 通过示例1可知, 我们写代码的目的是在数组中找到一个最大值,并且返回来 ; 我们很容易的会想到创建一个变量:int min = 0; 然后遍历整个数组,依次比较把一个最小值

    2024年01月19日
    浏览(47)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包