【中等】在有序旋转数组中找到一个数-Java

该文章提供了一个关于人工智能教程的示例,讲解了如何在可能经过旋转的有序数组中使用二分查找法寻找特定数值。文章详细阐述了处理旋转数组的中等难度问题,包括识别断点和优化查找策略,即使在数组有重复元素的情况下也能应用此方法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

分享一个大牛的人工智能教程。零基础!通俗易懂!风趣幽默!希望你也加入到人工智能的队伍中来!请轻击人工智能教程大家好!欢迎来到我的网站! 人工智能被认为是一种拯救世界、终结世界的技术。毋庸置疑,人工智能时代就要来临了,科… 继续阅读 前言https://www.captainai.net/troubleshooter

package live.every.day.ProgrammingDesign.CodingInterviewGuide.Other;

/**
 * 在有序旋转数组中找到一个数
 *
 * 【题目】
 * 有序数组arr可能经过一次旋转处理,也可能没有,且arr可能存在重复的数。例如,有序数组[1,2,3,4,5,6,7],可以旋转处理成
 * [4,5,6,7,1,2,3]等。给定一个可能旋转过的有序数组arr,再给定一个数num,返回arr中是否含有num。
 *
 * 【难度】
 * 中等
 *
 * 【解答】
 * 为了方便描述,我们把没经过旋转前,有序数组arr最左边的数,在经过旋转之后所处的位置叫作"断点"。例如,题目例子里的数组,
 * 旋转后断点在1所处的位置,也就是位置4。如果一个数组没有经过旋转处理,断点在位置0。
 * 本文提供的方式做到了尽可能多地利用二分查找,但是最差情况下仍无法避免O(N)的时间复杂度,以下是具体过程:
 * 1.用low和high变量表示arr上的一个范围,每次判断num是否在arr[low..high]上,初始时,low=0,high=arr.length-1,
 * 然后进入步骤2。
 * 2.如果low>high,直接进入步骤5,否则令变量mid=(low+high)/2,也就是二分的位置。如果arr[mid]==num,直接返回true,
 * 否则进入步骤3。
 * 3.此时arr[mid]!=num。如果发现arr[low]、arr[mid]、arr[high]三个值不都相等,直接进入步骤4。如果发现三个值都相等,
 * 此时根本无法知道断点的位置在mid的哪一侧。例如:7(low)...7(mid)...7(high),举一个极端的例子,如果这个数组中只有一
 * 个值为num的数,其他的数都是7,那么num除了不在low、mid、high这三个位置以外,剩下的位置都是可能的。所以num也既可能在
 * mid的左边,也可能在右边。所以进行这样的处理:
 * 1)只要arr[low]等于arr[mid],就让low不断地向右移动(low++),如果在low移到mid的期间,都没有发现arr[low]和
 * arr[mid]不等的情况,说明num只可能在mid的右侧,因为左侧全都扫过了,此时令low=mid+1,high不变,进入步骤2。
 * 2)只要arr[low]等于arr[mid],就让low不断地向右移动(low++),如果期间一旦发现arr[low]和arr[mid]不等,说明在此时
 * 的arr[low(递增后的)..mid..right]上是可以判断出断点位置的,则进入步骤4。
 * 4.此时arr[mid]!=num,并且arr[low]、arr[mid]、arr[high]三个值不都相等,那么是一定可以二分的,具体判断如下:
 * 如果arr[low]!=arr[mid],如何判断断点位置呢?分以下两种情况。
 * 情况一:arr[mid]>arr[low],断点一定在mid的右侧,此时arr[low..mid]上有序。
 * 1)如果num>=arr[low]&&num<arr[mid],说明num只需要在arr[low..mid]上寻找。这是因为如果
 * num==arr[low]&&num<arr[mid]。很显然,在arr[low..mid]上能找到num。如果num>arr[low]&&num<arr[mid],则说明
 * 断点在右侧,假设断点在mid和high之间的break位置上,那么arr[mid..break-1]上的值都大于或等于arr[mid],也都大于num,
 * arr[break..high]上的值都小于或等于arr[low],也都小于num,所以整个mid的右侧都没有num。综上所述,num只需要在
 * arr[low..mid]上寻找,令high=mid-1,进入步骤2。
 * 2)若不满足条件1),说明要么num<arr[low],此时整个arr[low..mid]上都大于num。要么num>arr[mid],此时整个
 * arr[low..mid]上都小于num。无论是哪种,num都只可能出现在mid的右侧,所以令low=mid+1,进入步骤2。
 * 情況二:不满足情况一则断点一定在mid位置或在mid左侧,不管是哪一种,arr[mid..high]都一定是有序的。
 * 1)如果num>arr[mid]&&num<=arr[high]与情况一的条件1)相同的分析方式,令low=mid+1,进入步骤2。
 * 2)若不满足条件1),与情况一的条件2)相同的分析方式,令high=mid-1,进入步骤2。
 * 如果arr[mid]!=arr[high],如何判断断点的位置呢?和arr[low]!=arr[mid]时一样的分析方式,这里不再详述。
 * 5.如果low在high的右边(low>high),说明arr中没有num,返回false。
 * 全部的过程请参看如下代码中的isContains方法。
 *
 * @author Created by LiveEveryDay
 */

public class InOrderedRotatedArrayFindNum {

    public static boolean isContains(int[] arr, int num) {
        int low = 0;
        int high = arr.length - 1;
        int mid = 0;
        while (low <= high) {
            mid = (low + high) >> 1;
            if (arr[mid] == num) {
                return true;
            }
            if (arr[low] == arr[mid] && arr[mid] == arr[high]) {
                while (low != mid && arr[low] == arr[mid]) {
                    low++;
                }
                if (low == mid) {
                    low = mid + 1;
                    continue;
                }
            }
            if (arr[low] != arr[mid]) {
                if (arr[mid] > arr[low]) {
                    if (num >= arr[low] && num < arr[mid]) {
                        high = mid - 1;
                    } else {
                        low = mid + 1;
                    }
                } else {
                    if (num > arr[mid] && num <= arr[high]) {
                        low = mid + 1;
                    } else {
                        high = mid - 1;
                    }
                }
            } else {
                if (arr[mid] < arr[high]) {
                    if (num > arr[mid] && num <= arr[high]) {
                        low = mid + 1;
                    } else {
                        high = mid - 1;
                    }
                } else {
                    if (num >= arr[low] && num < arr[mid]) {
                        high = mid - 1;
                    } else {
                        low = mid + 1;
                    }
                }
            }
        }
        return false;
    }

    public static void main(String[] args) {
        int[] arr = {4, 5, 6, 7, 1, 2, 3};
        int num = 6;
        System.out.printf("Is contains num? %s", isContains(arr, num));
    }

}

// ------ Output ------
/*
Is contains num? true
*/
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值