leetcode 1095. 山脉数组中查找目标值 (二分法的三种范式)及应用

传送门

/**
 * // This is the MountainArray's API interface.
 * // You should not implement it, or speculate about its implementation
 * class MountainArray {
 *   public:
 *     int get(int index);
 *     int length();
 * };
 */

class Solution {
public:
    int upbinsearch(MountainArray & mountainArr,int target,int l,int r){
        while(l<=r){
            int m=l+(r-l)/2;
            // 在循环体中查找
            if(mountainArr.get(m)==target){
                return m;
            }
            else if(mountainArr.get(m)>target){
                r=m-1;
            }
            else{
                l=m+1;
            }
        }
        return -1;
    }
    int dwbinsearch(MountainArray & mountainArr,int target,int l,int r){
        while(l<=r){
            int m=l+(r-l)/2;
            // 在循环体中查找
            if(mountainArr.get(m)==target){
                return m;
            }
            else if(mountainArr.get(m)<target){
                r=m-1;
            }
            else{
                l=m+1;
            }
        }
     
        return -1;
    }
    int findInMountainArray(int target, MountainArray &mountainArr) {
        int l=0;
        int r=mountainArr.length()-1;
        int len=r;
        while(l<r){
            //  在循环体中缩小区间
            int mid=l+(r-l)/2;
            if(mountainArr.get(mid)<mountainArr.get(mid+1)){
                l=mid+1;
            }
            else 
                r=mid;
        }
        int peak=l;
        // cout<<peak<<endl;
        int index=upbinsearch(mountainArr,target,0,peak);
        if(index!=-1) 
            return index;
        return dwbinsearch(mountainArr,target,peak+1,len);
        
    }
};

在这里插入图片描述
在这里插入图片描述
下取整时,left=mid ,当进入left=mid 时,死循环
上取整 时, right=mid, 当进入right=mid 时,死循环

在这里插入图片描述
在这里插入图片描述

异或:1按位取反,0保持

/**
 * // This is the MountainArray's API interface.
 * // You should not implement it, or speculate about its implementation
 * class MountainArray {
 *   public:
 *     int get(int index);
 *     int length();
 * };
 */

class Solution {
public:
    int binsearch(MountainArray & mountainArr,int target,int l,int r,bool flag){
        while(l<=r){
            int m=l+(r-l)/2;
            // 在循环体中查找
            if(mountainArr.get(m)==target){
                return m;
            }
            else if((mountainArr.get(m)> target)^flag){
                r=m-1;
            }
            else{
                l=m+1;
            }
        }
        return -1;
    }
    int findInMountainArray(int target, MountainArray &mountainArr) {
        int l=0;
        int r=mountainArr.length()-1;
        int len=r;
        while(l<r){
            //  在循环体中缩小区间
            int mid=l+(r-l)/2;
            if(mountainArr.get(mid)<mountainArr.get(mid+1)){
                l=mid+1;
            }
            else 
                r=mid;
        }
        int peak=l;
      
       
        int index=binsearch(mountainArr,target,0,peak,0);
        if(index!=-1) 
            return index;
        return binsearch(mountainArr,target,peak+1,len,1);
     
        
    }
};

python 学习

# """
# This is MountainArray's API interface.
# You should not implement it, or speculate about its implementation
# """
class MountainArray:
    def __init__(self, arr):
        self.arr = arr
        self.size = len(arr)

    def get(self, index: int) -> int:
        return self.arr[index]

    def length(self) -> int:
        return self.size


class Solution:

    # 特别注意:3 个辅助方法的分支出奇地一样,因此选中位数均选左中位数,才不会发生死循环

    def findInMountainArray(self, target: int, mountain_arr: 'MountainArray') -> int:
        size = mountain_arr.length()
        # 步骤 1:先找到山顶元素所在的索引
        mountaintop = self.__find_mountaintop(mountain_arr, 0, size - 1)
        # 步骤 2:在前有序且升序数组中找 target 所在的索引
        res = self.__find_from_sorted_arr(mountain_arr, 0, mountaintop, target)
        if res != -1:
            return res
        # 步骤 3:如果步骤 2 找不到,就在后有序且降序数组中找 target 所在的索引
        return self.__find_from_inversed_arr(mountain_arr, mountaintop + 1, size - 1, target)

    def __find_mountaintop(self, mountain_arr: 'MountainArray', l: int, r: int):
        # 返回山顶元素
        while l < r:
            mid = l + (r - l) // 2
            # 取左中位数,因为进入循环,数组一定至少有 2 个元素
            # 因此,左中位数一定有右边元素,数组下标不会发生越界
            if mountain_arr.get(mid) < mountain_arr.get(mid + 1):
                # 如果当前的数比右边的数小,它一定不是山顶
                l = mid + 1
            else:
                r = mid
        # 根据题意,山顶元素一定存在,因此退出 while 循环的时候,不用再单独作判断
        return l

    def __find_from_sorted_arr(self, mountain_arr: 'MountainArray', l: int, r: int, target: int):
        # 在前有序且升序数组中找 target 所在的索引
        while l < r:
            mid = l + (r - l) // 2
            if mountain_arr.get(mid) < target:
                l = mid + 1
            else:
                r = mid
        # 因为不确定区间收缩成 1 个数以后,这个数是不是要找的数,因此单独做一次判断
        if mountain_arr.get(l) == target:
            return l
        return -1

    def __find_from_inversed_arr(self, mountain_arr: 'MountainArray', l: int, r: int, target: int):
        # 在后有序且降序数组中找 target 所在的索引
        while l < r:
            mid = l + (r - l) // 2
            # 与 __find_from_sorted_arr 方法不同的地方仅仅在于由原来的小于号改成大于号
            if mountain_arr.get(mid) > target:
                l = mid + 1
            else:
                r = mid
        if mountain_arr.get(l) == target:
            return l
        return -1


if __name__ == '__main__':
    arr = [1, 2, 3, 4, 5, 3, 1]
    mountain_array = MountainArray(arr)
    target = 3
    solution = Solution()
    res = solution.findInMountainArray(target, mountain_array)
    print('res', res)

作者:liweiwei1419
链接:https://leetcode-cn.com/problems/find-in-mountain-array/solution/shi-yong-chao-hao-yong-de-er-fen-fa-mo-ban-python-/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

java学习

/**
 * // This is MountainArray's API interface.
 * // You should not implement it, or speculate about its implementation
 */

interface MountainArray {
    public int get(int index);

    public int length();
}


class MountainArrayImpl implements MountainArray {
    private int[] arr;
    private int size;

    public MountainArrayImpl(int[] arr) {
        this.arr = arr;
        this.size = this.arr.length;
    }

    @Override
    public int get(int index) {
        return this.arr[index];
    }

    @Override
    public int length() {
        return this.size;
    }

}

class Solution {

    // 特别注意:3 个辅助方法的分支出奇地一样,因此选中位数均选左中位数,才不会发生死循环

    public int findInMountainArray(int target, MountainArray mountainArr) {
        int size = mountainArr.length();
        // 步骤 1:先找到山顶元素所在的索引
        int mountaintop = findMountaintop(mountainArr, 0, size - 1);
        // 步骤 2:在前有序且升序数组中找 target 所在的索引
        int res = findFromSortedArr(mountainArr, 0, mountaintop, target);
        if (res != -1) {
            return res;
        }
        // 步骤 3:如果步骤 2 找不到,就在后有序且降序数组中找 target 所在的索引
        return findFromInversedArr(mountainArr, mountaintop + 1, size - 1, target);
    }

    private int findMountaintop(MountainArray mountainArr, int l, int r) {
        // 返回山顶元素
        while (l < r) {
            int mid = l + (r - l) / 2;
            // 取左中位数,因为进入循环,数组一定至少有 2 个元素
            // 因此,左中位数一定有右边元素,数组下标不会发生越界
            if (mountainArr.get(mid) < mountainArr.get(mid + 1)) {
                // 如果当前的数比右边的数小,它一定不是山顶
                l = mid + 1;
            } else {
                r = mid;
            }
        }
        // 根据题意,山顶元素一定存在,因此退出 while 循环的时候,不用再单独作判断
        return l;
    }

    private int findFromSortedArr(MountainArray mountainArr, int l, int r, int target) {
        // 在前有序且升序数组中找 target 所在的索引
        while (l < r) {
            int mid = l + (r - l) / 2;
            if (mountainArr.get(mid) < target) {
                l = mid + 1;
            } else {
                r = mid;
            }

        }
        // 因为不确定区间收缩成 1个数以后,这个数是不是要找的数,因此单独做一次判断
        if (mountainArr.get(l) == target) {
            return l;
        }
        return -1;
    }

    private int findFromInversedArr(MountainArray mountainArr, int l, int r, int target) {
        // 在后有序且降序数组中找 target 所在的索引
        while (l < r) {
            int mid = l + (r - l) / 2;
            // 与 findFromSortedArr 方法不同的地方仅仅在于由原来的小于号改成大于好
            if (mountainArr.get(mid) > target) {
                l = mid + 1;
            } else {
                r = mid;
            }

        }
        // 因为不确定区间收缩成 1个数以后,这个数是不是要找的数,因此单独做一次判断
        if (mountainArr.get(l) == target) {
            return l;
        }
        return -1;
    }

    public static void main(String[] args) {
        int[] arr = {1, 2, 3, 4, 5, 3, 1};
        int target = 3;
        MountainArray mountainArray = new MountainArrayImpl(arr);

        Solution solution = new Solution();
        int res = solution.findInMountainArray(target, mountainArray);
        System.out.println(res);
    }
}

作者:liweiwei1419
链接:https://leetcode-cn.com/problems/find-in-mountain-array/solution/shi-yong-chao-hao-yong-de-er-fen-fa-mo-ban-python-/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值