首页 > 其他分享 >搜索旋转排序数组习题分析

搜索旋转排序数组习题分析

时间:2024-11-29 19:29:00浏览次数:5  
标签:right nums mid 旋转 查找 数组 习题 排序 left

习题:(leetcode33)

整数数组 nums 按升序排列,数组中的值 互不相同 。

在传递给函数之前,nums 在预先未知的某个下标 k0 <= k < nums.length)上进行了 旋转,使数组变为 [nums[k], nums[k+1], ..., nums[n-1], nums[0], nums[1], ..., nums[k-1]](下标 从 0 开始 计数)。例如, [0,1,2,4,5,6,7] 在下标 3 处经旋转后可能变为 [4,5,6,7,0,1,2] 。

给你 旋转后 的数组 nums 和一个整数 target ,如果 nums 中存在这个目标值 target ,则返回它的下标,否则返回 -1 。

你必须设计一个时间复杂度为 o(log n) 的算法解决此问题。

二分查找:

二分查找(Binary Search)是一种在有序数组中查找某一特定元素的搜索算法。二分查找的过程从数组的中间元素开始,如果中间元素正好是要查找的元素,则搜索过程结束;如果某一特定元素大于或小于中间元素,则搜索过程将在数组的大于或小于中间元素的那一半区域中继续,以此类推,直到找到要查找的元素,或者剩下的半区域为空。

二分查找主要分为两种,一种是值域左闭右开,一种是值域左闭右闭。

二者不同点:对于左闭右开,就是在while循环中将条件写为left<right,而左闭右闭则是left<=right。

而其中的right更改值时的语句二者也是不同,左闭右开:right=mid(mid是中间节点),

左闭右闭:right=mid-1。

分析:

此题有两个关键,一是nums 按升序排列,数组中的值都不同,二是复杂度为O(log n)。

我们可以以二分查找为基础,通过先找到旋转点后,再进行对目标target的查找。

在查找旋转点时,则使用左闭右开,因为无法确定mid是否是旋转点,所以要将mid的值保留到下次循环查找即right=mid。

而当找到旋转点后,与target进行比较得到区间,再在得到的区间内进行查找。此时就可使用左闭右闭的形式,进行查找即循环条件写为:left<=right,意味着二分查找的搜索空间已经缩小到了一个元素。在这种情况下,我们需要检查这个元素是否是目标值。如果使用功能left<right作为条件,我们将错过检查这个元素的机会。

代码分析:

class Solution {
public:
    int search(vector<int>& nums, int target) {
        int n = nums.size(); // 获取数组的大小
        if (n == 0) return -1; // 如果数组为空,直接返回-1
        if (n == 1) return nums[0] == target ? 0 : -1; // 如果数组只有一个元素,检查它是否是目标值

        int left = 0, right = n - 1; // 初始化二分查找的左右边界
        // 先找到旋转点
        while (left < right) {
            int mid = left + (right - left) / 2; // 计算中间位置,防止溢出
            if (nums[mid] > nums[right]) {
                // 如果中间元素大于右边界元素,说明旋转点在中间位置的右侧
                left = mid + 1; // 更新左边界为中间位置的右侧
            } else {
                // 如果中间元素小于等于右边界元素,说明旋转点在中间位置的左侧或就是中间位置
                right = mid; // 更新右边界为中间位置,不能减1,因为mid可能是旋转点
            }
        }
        // 旋转点的位置,此时left等于right
        int rotate_index = left;

        // 根据旋转点确定搜索区间
        left = 0;
        right = n - 1;
        if (target >= nums[rotate_index] && target <= nums[n - 1]) {
            // 如果目标值在旋转点右侧的区间内
            left = rotate_index; // 更新左边界为旋转点
        } else {
            // 如果目标值在旋转点左侧的区间内
            right = rotate_index; // 更新右边界为旋转点
        }

        // 在确定的区间内进行二分查找
        while (left <= right) {
            int mid = left + (right - left) / 2; // 计算中间位置
            if (nums[mid] == target) {
                // 如果中间位置的元素是目标值,返回其索引
                return mid;
            } else if (nums[mid] < target) {
                // 如果中间位置的元素小于目标值,更新左边界为中间位置的右侧
                left = mid + 1;
            } else {
                // 如果中间位置的元素大于目标值,更新右边界为中间位置的左侧
                right = mid - 1;
            }
        }
        // 如果循环结束还没有找到目标值,返回-1
        return -1;
    }
};

标签:right,nums,mid,旋转,查找,数组,习题,排序,left
From: https://blog.csdn.net/m0_74313252/article/details/144120859

相关文章

  • 岛屿数量习题分析
    习题:(leetcode200)给你一个由'1'(陆地)和'0'(水)组成的的二维网格,请你计算网格中岛屿的数量。岛屿总是被水包围,并且每座岛屿只能由水平方向和/或竖直方向上相邻的陆地连接形成。此外,你可以假设该网格的四条边均被水包围。分析:使用方法为DFS,将遇到的“岛屿”更改为0,表示已探......
  • 算法:数组 #241125
    算法:数组理论二分查找移除元素二分查找题目链接:leetcode#704给定一个n个元素有序的(升序)整型数组nums和一个目标值target,写一个函数搜索nums中的target,如果目标值存在返回下标,否则返回-1。题目的前置条件为n个有序的元素,故可通过二分查找解题找到中......
  • 查找数组中相似字段(数组里面某个值相似归类到一起)
    例如↓数组中每条数据的url字段相似arr=[{id:0,dir:'/edit/aaaa/bbbb/cccc/dddd/20231123',title:'第一条数据'},{id:1,dir:'/edit/aaaa/bbbb/cccc/dddd/20241011',title:'第二条数据'},......
  • 力扣刷题——3251. 单调数组对的数目 II
    考虑arr1可以取到的数字组合数,从0到i+1位置的合法的arr1组合数,可以从0到i的组合数得到。因此可以想到用动态规划解决问题,使用一个数组dp[i][j]代表arr1[i]=j时,前i+1个数字有多少个组合。这样一来,最终的答案即为sum(dp[n-1][0...M],其中M为nums中最大值。根据这个思路写出一个简......
  • php 对空数组元素??并进行运算,可能触发 Undefined index 错误
    对空数组元素??并进行运算,可能触发Undefinedindex错误$TotalGb=$TotalGroupBrand[$brandNameEn]??[];$quantity=$TotalGb['stock']??0+$TotalGb['unshipped_qty']??0;"#报错:Undefinedindex:unshipped_qty",代码中的错误"Undefinedindex:......
  • 蓝桥2128 重新排序(差分)
    给定一个数组A和一些查询Li和Ri,求数组第Li个至第Ri个元素之和。小蓝觉得这个问题很无聊,于是他想重新排列一下数组,使得最终每个查询结果的和尽可能地大。小蓝想知道相比原数组,所有查询结果的总和最多可以增加多少?大致思路:m次查询,每次求Li至Ri之和,我们可以用差分统计每个位......
  • Java 的数据结构:从数组到链表的基础实现
    Java的数据结构:从数组到链表的基础实现在Java编程中,数据结构是指用来存储和组织数据的方式。正确选择和使用数据结构能提高程序的效率和可扩展性。在这篇文章中,我们将深入探讨Java中两种基础数据结构:数组(Array)和链表(LinkedList),并通过实例讲解它们的基本实现、优缺点......
  • 举例说明js创建数组有哪些方法?
    JS创建数组有多种方法,以下列举几种常见的方式并举例说明:数组字面量(ArrayLiteral):这是最常用且最简洁的方法。使用方括号[]包含数组元素,元素之间用逗号分隔。constarr1=[1,2,3,"hello",true,{name:"John"}];//包含不同数据类型的数组constemptyArr=......
  • 快速排序两种写法的注意点
    1.自创写法(根据快速排序原理,使用while)这里有一组hack数据就是数组中存在两个元素值相等的情况,此时backup[i]和backup[j]相等,此时交换之后如果不写i++,j++就会造成i,j指针在下一次循环中,仍然会卡在原来的位置,从而造成死循环。所以每两个元素交换完了之后一定要保证指......
  • 讲扁平化的数组数据转为树形结构
    核心调用自己exportconsthandleTree=(data:any[],id?:string,parentId?:string,children?:string)=>{//校验是不是数组if(!Array.isArray(data)){console.warn('datamustbeanarray')return[]}//配置对象,有则用,无则默认co......