IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 数据结构与算法 -> 旋转数组相关算法 -> 正文阅读

[数据结构与算法]旋转数组相关算法

旋转数组

1.查找最小值

题目描述

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

  • 若旋转 4 次,则可以得到 [4,5,6,7,0,1,2]
  • 若旋转 7 次,则可以得到 [0,1,2,4,5,6,7]

注意,数组 [a[0], a[1], a[2], ..., a[n-1]] 旋转一次 的结果为数组 [a[n-1], a[0], a[1], a[2], ..., a[n-2]]

给你一个元素值 互不相同 的数组 nums ,它原来是一个升序排列的数组,并按上述情形进行了多次旋转。请你找出并返回数组中的 最小元素

你必须设计一个时间复杂度为 O(log n) 的算法解决此问题。
在这里插入图片描述

(1)数组中的值各不相同

算法分析:

因为需要在O(log n)时间内完成算法,所以首先考虑二分。

旋转数组可以分为左右两个部分,左右两个部分的序列都是区间严格递增的,而最小值必落在右边的区间。

因此我们可以判断此时mid在左右哪个区间,分两种情况。

  • 如果mid大于右区间right,说明mid左半区,就将left移动到mid + 1,因为最小值不可能在左半区
  • 如果mid小于右区间right,如果mid右半区,则当前mid有可能是最小值,此时将right移动到mid

在这里插入图片描述

代码实现:

    public int findMin(int[] nums) {
        int left = 0;
        int right = nums.length - 1;
        while(left < right) {
            int mid = left + (right - left) / 2;
            // 如果mid在左半区
            if(nums[mid] > nums[right]) {
                left = mid + 1;
                
            // 如果mid在右半区
            } else {
                right = mid;
            }
        }
        return nums[left];
    }

(2)数组中的值可能相同

算法分析:

因此我们可以判断此时mid在左右哪个区间,分三种情况讨论。

  • 如果mid大于右区间right,说明当前mid左半区,此时将left移动到mid + 1,因为最小值不可能在左半区
  • 如果mid小于等于右区间right,说明当前mid右半区,则当前mid有可能是最小值,此时将right移动到mid
  • 如果mid等于右区间right,即nums[mid] == nums[right],此时说明right的值可以被mid取代,所以右区间减一做缩容操作

代码实现:

    public int findMin(int[] nums) {
        int left = 0;
        int right = nums.length - 1;
        while (left < right) {
            int mid = left + (right - left) / 2;
            // 左半区
            if(nums[mid] > nums[right]){
                left = mid + 1;
                
             // 右半区
            } else if(nums[mid] < nums[right]) {
                right = mid;
                
         
            } else {
                right--;
            }
        }
        return nums[left];
    }

2.查找指定值target

题目描述:

整数数组 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) 的解决方案。
在这里插入图片描述

(1)数组中的值各不相同

算法分析:

旋转数组可以分为左右两个部分,左右两个部分的序列都是区间严格递增的,分三种情况讨论。

  • 当前mid的值等于target,找到目标值,返回下标

  • 当前mid的值大于right,此时mid落在左半区,然后判断target是否比mid小,如果targetmid左边,就将right移动到mid-1,否则将left移动到mid+1

  • 当前mid的值小于right,此时mid落在右半区,然后判断target是否比mid大,如果target在mid右边,就将left移动到mid+1,否则将right移动到mid-1

代码实现:

	public int search(int[] nums, int target) {
        int left = 0;
        int right = nums.length - 1;
        while(left <= right) {
            int mid = left + (right - left) / 2;
            if(nums[mid] == target) {
                return mid;
            }
            // 左半区
            if(nums[mid] > nums[right]) {
                if(target >= nums[left] && target < nums[mid]) {
                    right = mid - 1;
                } else {
                    left = mid + 1;
                }
                
            // 右半区
            } else {
                if(target <= nums[right] && target > nums[mid]) {
                    left = mid + 1;
                } else {
                    right = mid - 1;
                }
            }
        }
        return -1;
    }

(2)数组中的值可能相同

算法分析:

旋转数组可以分为左右两个部分,分三种情况讨论。

  • 当前mid的值等于target,找到目标值,返回下标

  • 如果mid等于右区间right和左区间left,即nums[mid] == nums[right] && nums[mid] == nums[left],此时说明rightleft的值均可以被mid取代,所以左右区间各减一做缩容操作

  • 当前mid的值大于right,此时mid落在左半区,然后判断target是否比mid小,如果targetmid左边,就将right移动到mid-1,否则将left移动到mid+1

  • 当前mid的值小于或等于right,当mid==right,因为mid已经不等于left了,否则就满足了条件二,所以此时mid落在右半区,然后判断target是否比mid大,如果target在mid右边,就将left移动到mid+1,否则将right移动到mid-1

	public int search(int[] nums, int target) {
        int left = 0;
        int right = nums.length - 1;
        while(left <= right) {
            int mid = left + (right - left) / 2;
            if(nums[mid] == target) {
                return mid;
            }
            if(nums[mid] == nums[left] && nums[mid] == nums[right]) {
                right--;
                left++;
            } else if(nums[mid] >= nums[left]) {
                if(target >= nums[left] && target < nums[mid]) {
                    right = mid - 1;
                } else {
                    left = mid + 1;
                }
            } else {
                if(target <= nums[right] && target > nums[mid]) {
                    left = mid + 1;
                } else {
                    right = mid - 1;
                }
            }
        }
        return -1;
    }
  数据结构与算法 最新文章
【力扣106】 从中序与后续遍历序列构造二叉
leetcode 322 零钱兑换
哈希的应用:海量数据处理
动态规划|最短Hamilton路径
华为机试_HJ41 称砝码【中等】【menset】【
【C与数据结构】——寒假提高每日练习Day1
基础算法——堆排序
2023王道数据结构线性表--单链表课后习题部
LeetCode 之 反转链表的一部分
【题解】lintcode必刷50题<有效的括号序列
上一篇文章      下一篇文章      查看所有文章
加:2022-04-15 00:24:47  更:2022-04-15 00:28:28 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/26 7:23:10-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码