当前位置: 首页 > article >正文

【Leetcode 每日一题】81. 搜索旋转排序数组 II

问题背景

已知存在一个按非降序排列的整数数组 n u m s nums nums,数组中的值不必互不相同。
在传递给函数之前, n u m s nums nums 在预先未知的某个下标 k   ( 0 < = k < n u m s . l e n g t h ) k\ (0 <= k < nums.length) k (0<=k<nums.length) 上进行了 旋转 ,使数组变为 [ n u m s [ k ] , n u m s [ k + 1 ] , . . . , n u m s [ n − 1 ] , n u m s [ 0 ] , n u m s [ 1 ] , . . . , n u m s [ k − 1 ] ] [nums[k], nums[k+1], ..., nums[n-1], nums[0], nums[1], ..., nums[k-1]] [nums[k],nums[k+1],...,nums[n1],nums[0],nums[1],...,nums[k1]](下标 从 0 0 0 开始 计数)。例如, [ 0 , 1 , 2 , 4 , 4 , 4 , 5 , 6 , 6 , 7 ] [0,1,2,4,4,4,5,6,6,7] [0,1,2,4,4,4,5,6,6,7] 在下标 5 5 5 处经旋转后可能变为 [ 4 , 5 , 6 , 6 , 7 , 0 , 1 , 2 , 4 , 4 ] [4,5,6,6,7,0,1,2,4,4] [4,5,6,6,7,0,1,2,4,4]
给你 旋转后 的数组 n u m s nums nums 和一个整数 t a r g e t target target,请你编写一个函数来判断给定的目标值是否存在于数组中。如果 n u m s nums nums 中存在这个目标值 t a r g e t target target,则返回 t r u e true true,否则返回 f a l s e false false
你必须尽可能减少整个操作步骤。

数据约束

  • 1 ≤ n u m s . l e n g t h ≤ 5000 1 \le nums.length \le 5000 1nums.length5000
  • − 1 0 4 ≤ n u m s [ i ] ≤ 1 0 4 -10 ^ 4 \le nums[i] \le 10 ^ 4 104nums[i]104
  • 题目数据保证 n u m s nums nums 在预先未知的某个下标上进行了旋转
  • − 1 0 4 ≤ t a r g e t ≤ 1 0 4 -10 ^ 4 \le target \le 10 ^ 4 104target104

解题过程

这题是在 搜索旋转排序数组 的基础上增加了元素可重复这个条件,仍然可以参考无重复元素的实现,先找到最小值,再到相应的部分数组中去找结果。
然而之前的二分答案法是每次与数组的最后一个元素比较大小,如果遇到当前元素与数组中最后一个元素重复的情况,就没有办法确定要往那个方向继续执行了。
考虑到如果有重复元素出现上述情况,它们会在旋转之后分布在数组两头。
这时候可以反复比较范围左边界的元素和数组中最后一个元素,发现重复时就将范围中的首个元素去掉。
可能会出现两种情况,去掉的这个是要查找的目标,那它还有一个重复值在数组末尾,不影响结果;去掉的这个不是要查找的目标,那就无所谓了,也不影响结果。

这道题属于是经典的为了考知识点而一味地加限制,评价为出题把脑子出坏了。
道理很简单,去掉重复元素使得范围上可用二分查找这个过程,时间复杂度是 O ( N ) O(N) O(N) 这个量级的。
这就导致了,整个算法是无法达到 O ( l o g N ) O(logN) O(logN) 这样的水平了。
既然如此,还费劲巴拉的二分什么二分,直接遍历数组同样也只是需要 O ( N ) O(N) O(N) 的时间。

具体实现

二分查找

class Solution {
    public boolean search(int[] nums, int target) {
        int n = nums.length;
        int left = 0, right = n - 1;
        // 去掉二分范围内首尾的重复元素,注意 left != n - 1 这个条件,别把所有元素都去掉了
        while (left != n - 1 && nums[left] == nums[n - 1]) {
            left++;
        }
        // Leetcode 33.搜索旋转排序数组
        int minIndex = findMin(nums, left, right);
        if (target > nums[n - 1]) {
            return binarySearch(nums, target, 0, minIndex);
        }
        return binarySearch(nums, target, minIndex, n);
    }

    // Leetcode 153.找到数组中的最小值
    private int findMin(int[] nums, int left, int right) {
        int n = nums.length;
        while(left < right) {
            int mid = left + ((right - left) >> 1);
            if (nums[mid] > nums[n - 1]) {
                left = mid + 1;
            } else {
                right = mid;
            }
        }
        return left;
    }

    // Leetcode 35.搜索插入位置
    private boolean binarySearch(int[] nums, int target, int left, int right) {
        while (left < right) {
            int mid = left + ((right - left) >> 1);
            if (nums[mid] < target) {
                left = mid + 1;
            } else {
                right = mid;
            }
        }
        return nums[left] == target;
    }
}

直接遍历

class Solution {
    public boolean search(int[] nums, int target) {
        for (int num : nums) {
            if (num == target) {
                return true;
            }
        }
        return false;
    }
}

http://www.kler.cn/a/531147.html

相关文章:

  • 实验六 项目二 简易信号发生器的设计与实现 (HEU)
  • 深入浅出并查集(不相交集合实现思路)
  • 如何运行Composer安装PHP包 安装JWT库
  • Shadow DOM举例
  • 万字长文深入浅出负载均衡器
  • 知识库建设与知识管理实践对企业发展的助推作用探索
  • 【ChatGPT:开启人工智能新纪元】
  • 嵌入式硬件篇---HAL库内外部时钟主频锁相环分频器
  • Leetcode面试高频题分类刷题总结
  • GESP2023年9月认证C++六级( 第三部分编程题(2)小杨的握手问题)
  • BFS(广度优先搜索)——搜索算法
  • unity学习27:用Input接口去监测: 单点触摸和多点触摸
  • 虚幻基础17:动画层接口
  • 【C语言入门】解锁核心关键字的终极奥秘与实战应用(二)
  • js数据结构与算法
  • 房屋中介管理系统的设计与实现
  • 图形学笔记 - 5-光线追踪 - 辐射度量学
  • 高频文件更新数据实时同步实现原理
  • TensorFlow 示例平方米转亩
  • OpenCV:FLANN与暴力特征匹配
  • leetcode——二叉树的最近公共祖先(java)
  • HTML5教程之标签(2)
  • Java_类加载器
  • deep generative model stanford lecture note3 --- latent variable
  • 半导体器件与物理篇7 微波二极管、量子效应和热电子器件
  • SynchronousQueue 与 LinkedBlockingQueue区别及应用场景