• 33. 搜索旋转排序数组


    题目描述

    假设按照升序排序的数组在预先未知的某个点上进行了旋转。

    ( 例如,数组 [0,1,2,4,5,6,7] 可能变为 [4,5,6,7,0,1,2] )。

    搜索一个给定的目标值,如果数组中存在这个目标值,则返回它的索引,否则返回 -1 。

    你可以假设数组中不存在重复的元素。

    你的算法时间复杂度必须是 O(log n) 级别。

    示例 1:

    输入: nums = [4,5,6,7,0,1,2], target = 0
    输出: 4

    示例 2:

    输入: nums = [4,5,6,7,0,1,2], target = 3
    输出: -1

    算法

    说实话,看到评论中有人在讨论这题的意义何在,接着给出了遍历寻找的O(n)复杂度的3行代码,下面还有6、7个人点赞,我是十分无语的。

    题目既然给出算法时间复杂度必须是 O(log n) 级别,且原数组是有序变形而来,那么能想到的第一解决方案是二分查找

    二分查找

    前提:数组从小到大升序

    """left
    ight分别为数组nums的首末指针, target是要寻找的数"""
    while (left <= right):
        mid = (left + right) / 2
        if (nums[mid] == target):
            return mid
        if (nums[mid] > target):
            right = mid - 1
        else
            left = mid + 1
    # 如果跳出循环还没有找到这个数,说明数组中没有target,返回-1
    return -1;
    

    目前的数组nums并不是从小到大排好序的,而是间断性的有序,如4,5,6,7,0,1,2。这里仍可以借鉴二分查找的思想,只不过对mid要增加些许判断条件

    原数组有序的情况下是0,1,2,3,4,5,6,7,旋转过后分为几种情况,即小 大 小、大 小 大的两种形式,对应位置为letfmid ight这3个指针。小到大还是正常从小到大的顺序,在这一区域中仍可以用正常的二分思想确定left和right。在另一边大到小的乱序中,这需要根据nums[mid]和边界值的判断来确定left和right。详细注释给在代码中

    代码

    class Solution {
    public:
        int search(vector<int>& nums, int target) {
            /*** 利用二分查找求解问题 ***/
            
            // 三个指针
            int left, right, mid;
            
            // 赋初值
            left = 0, right = nums.size() - 1;
    
            // 循环开始
            while (left <= right)
            {
                // 计算中间位置的下标
                mid = (left + right) / 2;
    
                // 分别判断3个指针是否有目标值
                if (nums[mid] == target)
                   return mid;
                if (nums[left] == target)
                    return left;
                if (nums[right] == target)
                    return right;
                
                // 如果当前判断的这段数组满足nums[left] < nums[right],那么说明这段数组的顺序是从小到大排序的,形如0,1,2,3,4中,0 < 4是成立的
                if (nums[left] < nums[right])
                {
                    // 对于正常从小到大排序的数组二分查找
                    if(nums[mid] > target)
                        right = mid - 1;
                    else
                        left = mid + 1;
                }
                // 如果这段数组满足nums[left] > nums[right],那么说明这段数组的顺序并不是完全从小到大排序的,形如3,4,0,1,2中,3 > 2是成立的
                else
                {
                    if (nums[mid] < nums[right])
                    {
                        // 大 小 大,小到大这一段是正常从小到大排序的,如果target处于这一段,意味着下一次的判断需要移到这一段来寻找
                        if (target > nums[mid] && target < nums[right])
                            left = mid + 1;
                        else
                        // 否则,往左边段寻找
                            right = mid - 1;
                    }
                    else
                    {
                        // 小 大 小,同理,小到大是正常排序的,如果target处于这一段,意味着下一次的判断需要移到这一段来寻找
                        if (target < nums[mid] && target > nums[left])
                            right = mid - 1;
                        else
                         // 否则,往右边段寻找
                            left = mid + 1;
                    }
                }
            }
            // 前面都没能返回直至跳出循环说明要寻找的数并不在数组中,返回-1
            return -1;
        }
    };
    
  • 相关阅读:
    好用的镜头站下载工具
    300+Jquery, CSS, MooTools 和 JS的导航菜单资源
    股票入门2
    MEF学习笔记(6):出口和元数据
    MEF学习笔记(5):迟延加载导出部件
    WinForm控件复杂数据绑定常用数据源(如:Dictionary)(对Combobox,DataGridView等控件DataSource赋值的多种方法)
    wpf 多线程绑定控件
    HTTP 错误 404.2 Not Found 由于 Web 服务器上的“ISAPI 和 CGI 限制”列表设置,无法提供您请求的页面
    ADODB.Stream 错误 '800a0bbc' 写入文件失败。
    'System.Windows.StaticResourceExtension' threw an exception
  • 原文地址:https://www.cnblogs.com/shayue/p/10362512.html
Copyright © 2020-2023  润新知