LeetCode33: 搜索旋转排序数组

1. 题目描述

2. 题目分析

这道题与那道【LeetCode 153. 寻找旋转排序数组】中的最小值的区别在于,找最小值只可能在B数组中去寻找,right一定指向B中元素,而本体为搜索元素,right和left都有可能在A或者在B中,于是分类便复杂了很多。三个指针的相对关系如何确定呢,我们需要先定下一个,然后确定其他两个。

2.1 情况①: left在数组A中时,即nums[left] > nums[right]

  • 情况2.1.1 nums[left] <= target <= nums[mid], 则 right = mid -1;
  • 情况2.1.2 nums[left] <= nums[mid] && nums[left] > target, 则left = mid + 1;
  • 情况2.1.3 nums[left] > nums [mid] && nums[mid] < target, 则left = mid + 1;
  • 情况2.1.4 nums[left] <= target && nums[left] > nums[mid],则 right = mid -1;
  • 情况2.1.5 nums[left] > nums[mid] && target <= nums[mid], 则 right = mid -1;

2.2 情况②: left在数组B中时,即nums[left] < nums[right]

  • 情况2.2.1 nums[left] <= target <= nums[mid], 则 right = mid - 1;

  • 情况2.2.2 nums[mid] <= target <= nums[right], 则 left = mid + 1;


代码实现

class Solution {
    public int search(int[] nums, int target) {
        int left = 0, right = nums.length -1;

        while(left <= right) {
            int mid = left + ((right - left) >> 1) ;
     
            if(nums[mid] == target) {
                return mid;
            }

            if(nums[left] > nums[right]) {
              	// oh my gosh, what a lousy if conditional statement!
                if((nums[left] <= target && target <= nums[mid]) || (nums[left] <= target && nums[left] > nums[mid]) || nums[left] > nums[mid] && target <= nums[mid]) { 
                    right = mid - 1;            
                } else {
                    left = mid + 1;                
                }
            } else {
                if(nums[left] <= target && target <= nums[mid]) {
                    right = mid - 1;
         
                } else {
                    left = mid + 1;         
                }
            }
        }
        return -1;
    }
}

3. 思考和优化

由于条件语句太复杂了,我遗漏了两种情况,才勉强做出来。虽然很冗长,但在这一分析过程中我也有所收获。

Conclusion1: target 一定在 [left, right]区间内,并且是闭区间;

Conclusion2: 通过对上面分类的总结,得出了这样的结论:当target在 [left, mid) 区间内时(左闭右开,因为如果mid若指向target便会返回),right = mid - 1; 当target在 (mid, right] 区间内时(左开右闭,同理因为如果mid若指向target便会返回),left = mid + 1;

通过Conclusion2,我们可以对if语句再次优化。将原本【把left定在一个数组内】改为 【把mid定在一个数组内】,这样可以构造出:target在 [left, mid) 区间内 和 target在 (mid, right] 区间内。从而优化了条件判断,代码如下:

class Solution {
    public int search(int[] nums, int target) {
        int left = 0, right = nums.length -1;

        while(left <= right) {
            int mid = left + ((right - left) >> 1) ;
     
            if(nums[mid] == target) {
                return mid;
            }

            /*优雅多了,以后只用记住:
            * mid 在左边时,用left和mid把target夹住,让right = mid - 1, 否则 left = mid + 1;
            * mid 在右边时,用mid和right把target夹住,让left = mid + 1, 否则 right = mid - 1;
            */
            if (nums[mid] >= nums[left]) {
                if (nums[left] <= target && target < nums[mid]) {
                    right = mid - 1;
                } else {
                    left = mid + 1;
                }
            } else {
                if (nums[mid] < target && target <= nums[right]) {
                    left = mid + 1;
                } else {
                    right = mid - 1;
                }
            }
        }
        return -1;
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值