【算法】【算法杂谈】有序旋转数组中找到指定的数

文章介绍了如何在旋转排序数组中快速找到一个特定数值的问题,提供了Java语言的解决方案,采用二分查找并结合排除法优化。同时,作者表示正在学习C和C++语言的实现,并分享了对算法的理解和思考,强调了排除法在解决问题中的重要性。

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

前言

当前所有算法都使用测试用例运行过,但是不保证100%的测试用例,如果存在问题务必联系批评指正~

在此感谢左大神让我对算法有了新的感悟认识!

问题介绍

原问题
给定一个有序旋转数组,如[1,2,3,4,5,6,7]旋转后为[3,4,5,6,7,1,2],在给定一个数num,以最快的速度判断num是否在数组中。

解决方案

原问题
上一期中讲到求旋转数组中最小的值,这里求指定的值,思路大体一致
1、首先判断是否l、r、mid都相等,如果三个地方的值都相等,则无法判断出num是否在arr中,此时left单步前进直到left超过mid+1,进入下一轮循环或者arr[left]!=arr[mid]为止
2、其次如果三个值不都相等时,首先排除掉两端不相等的区间,再次排除掉存在断点的区间,最后排除掉确定不存在num的区间。
详情看代码和最终感悟。

代码编写

java语言版本

原问题:
方法一:




    /**
     * 二轮测试:判断num是否在旋转数组arr中
     * @param arr
     * @param num
     * @return
     */
    public static boolean findNumCp1(int[] arr, int num) {
        if (arr == null || arr.length == 0) {
            return false;
        }
        int left = 0;
        int right = arr.length-1;
        while (left < right) {
            int mid = (left + right) / 2;
            if (arr[mid] == num) {
                return true;
            }

            if (arr[mid] == arr[left] && arr[left] == arr[right]) {
                // 三个地方都相等,需要通过遍历打破这个局面
                while (arr[left] == arr[mid] && left < mid) {
                    left++;
                }
                if (left == mid) {
                    // 防止越界
                    left = mid+1;
                    continue;
                }
            }

            if (arr[left] != arr[mid]) {
                if (arr[left] < arr[mid]) {
                    if (num >= arr[left] && num < arr[mid]) {
                        right = mid-1;
                    }else {
                        left = mid + 1;
                    }
                }else {
                    if (num > arr[mid] && num <= arr[right]) {
                        left = mid + 1;
                    }else {
                        right = mid - 1;
                    }
                }
            }else {
                if (arr[mid] < arr[right]) {
                    if (num > arr[mid] && num < arr[right]) {
                        left = mid + 1;
                    }else {
                        right = mid - 1;
                    }
                }else {
                    if (num > arr[left] && num < arr[mid]) {
                        right = mid - 1;
                    }else {
                        left = mid + 1;
                    }
                }
            }
        }
        return false;
    }


    public static void main(String[] args) {
        System.out.println(findNumCp1(new int[]{2,3,4,5,1}, 0));
    }


c语言版本

正在学习中

c++语言版本

正在学习中

思考感悟

这道题其实用了排除法,我觉得他一直通过if (arr[left] < arr[mid]) { 这种判断是为了判断这个区间是否是单调递增的,如果arr[left] < arr[mid]说明left到mid不存在旋转点,还记得旋转数组的最重要的规律吧,如果arr[0] < arr[len]那么断点一定在arr[0],否则一定不成立,那么这个算法的精髓我觉得就是利用了这个比较的办法首先排除掉存在断点的区间,然后再次使用了if (num > arr[left] && num < arr[mid]) {这种方式排除掉num是否在连续区间,如果不在那么就应该在存在断点的那个区间内。

这道题不仅仅是一道简单的二分法题目,其中利用的思想确实值得借鉴,如果我们解决这类问题时,不一定获取要一下获取到结果,可以将能够判断的区间逐渐的缩小直到最后能够获取到结果为止,排除法值得借鉴

写在最后

方案和代码仅提供学习和思考使用,切勿随意滥用!如有错误和不合理的地方,务必批评指正~
如果需要git源码可邮件给2260755767@qq.com
再次感谢左大神对我算法的指点迷津!

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

元空间

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值