2020-12-25今日份牛客和leetcode==有重复数字的有序数组的二分查找+转动过的有序数组寻找目标值+旋转数组的最小数字

来源:链接:https://www.nowcoder.com/practice/7bc4a1c7c371425d9faa9d1b511fe193?tpId=188&&tqId=36844&rp=1&ru=/activity/oj&qru=/ta/job-code-high-week/question-ranking
声明:如果我侵犯了任何人的权利,请联系我,我会删除
欢迎高手来喷我

题目描述 请实现有重复数字的有序数组的二分查找。

输出在数组中第一个大于等于查找值的位置,如果数组中不存在这样的数,则输出数组长度加一。

示例1
输入 5,4,[1,2,4,4,5]
返回值 3
输出位置从1开始计算

代码,二分细节是魔鬼
import java.util.*; 
public class Solution {
    /**
     * 二分查找
     * @param n int整型 数组长度
     * @param v int整型 查找值
     * @param a int整型一维数组 有序数组
     * @return int整型
     */
    public int upper_bound_ (int n, int v, int[] a) { 
        //数组是排序好的, 那么判断最后一个值大于查找值,那么没有查找的意义了
        if(a[n-1] < v) return n+1;
        
        int left = 0, right = a.length;
        
        while(left < right){  
            int mid = left + (right - left)/2;
            if(a[mid] > v) right = mid;
            else if(a[mid] < v) left = mid+1; 
            //这里是应对重复值得思路
            //重复值,就顺序查找
            else{ //a[mid] == v
                while(mid >=0 && a[mid]==v) mid--;
                //为什么是+2???因为此时mid指向小于v的最后一个值,
                //mid+1指向等于v的第一个值,mid+1+1才是 符合“输出位置从1开始计算 ”的结果
                return mid+2;
            }
        }
        //输出位置从1开始计算 所以加1
        return left + 1;
    }
}
题目描述 转动过的有序数组寻找目标值

给出一个转动过的有序数组,你事先不知道该数组转动了多少
(例如,0 1 2 4 5 6 7可能变为4 5 6 7 0 1 2).
在数组中搜索给出的目标值,如果能在数组中找到,返回它的索引,否则返回-1。
假设数组中不存在重复项。
示例1
输入 [1],0
返回值 -1
示例2
输入 [3,2,1],1
返回值 2

代码 分情况:1 Arr[mid]=target 2:右半部有序 3:左半部有序

对旋转数组进行均等划分后,总有一边是有序的,如:

10 11 12 13 14 15 1 2 3
10 11 15 1 2 3 4 5 6 7 8
我们定位到有序的一边后,对比target与有序子数组的左右边界,就可以作出搜索左侧还是右侧的决策。

import java.util.*; 
public class Solution {
    /**
     * 
     * @param A int整型一维数组 
     * @param target int整型 
     * @return int整型
     */
    public int search (int[] A, int target) {
        // write code here
        int left = 0, right = A.length-1;
        while(left <= right){
            int mid = left + (right-left)/2;
            if(A[mid] == target) return mid;
            else if(A[mid] < A[right]){ //右半部有序
                if(A[mid] < target && target <= A[right]) left = mid+1;
                else right = mid - 1;
            }else{ //左半部有序
                if(target < A[mid] && A[left]<= target) right = mid-1;
                else left = mid + 1;
            }
        } 
        //不要想太多,找不到就返回-1
        return -1;
    }
}  
题目描述 剑指 Offer 11. 旋转数组的最小数字

链接:https://leetcode-cn.com/problems/xuan-zhuan-shu-zu-de-zui-xiao-shu-zi-lcof

把一个数组最开始的若干个元素搬到数组的末尾,我们称之为数组的旋转。输入一个递增排序的数组的一个旋转,输出旋转数组的最小元素。例如,数组 [3,4,5,1,2] 为 [1,2,3,4,5] 的一个旋转,该数组的最小值为1。
示例 1:
输入:[3,4,5,1,2]
输出:1
示例 2:
输入:[2,2,2,0,1]
输出:0

代码 细节的二分

我们考虑数组中的最后一个元素 x:在最小值右侧的元素,它们的值一定都小于等于 x;
而在最小值左侧的元素,它们的值一定都大于等于 x。因此,我们可以根据这一条性质,通过二分查找的方法找出最小值。

  • 第一种情况是 numbers[pivot]<numbers[high]。这说明 numbers[pivot] 是最小值右侧的元素,因此我们可以忽略二分查找区间的右半部分。
  • 第二种情况是 numbers[pivot]>numbers[high]。 这说明 numbers[pivot] 是最小值左侧的元素,因此我们可以忽略二分查找区间的左半部分。
  • 第三种情况是 numbers[pivot]==numbers[high]。由于重复元素的存在,我们并不能确定 numbers[pivot] 究竟在最小值的左侧还是右侧,
class Solution {
    public int minArray(int[] numbers) {
        int left = 0, right = numbers.length-1;
        while(left <= right){
            int mid = left + (right - left)/2;
            if(numbers[mid] < numbers[right]){
            //这里为什么不是right-1??因为mid这个值是小值,可能是我的所求,所以到带入下一次比较
                right = mid;
            }else if(numbers[mid] > numbers[right]){
                left = mid+1;
            }else{
                right--;
            }
        }
        return numbers[left];
        
    }
}
大神总结的二分,各种细节各种应用

详解二分查找算法https://www.cnblogs.com/kyoner/p/11080078.html

猜你喜欢

转载自blog.csdn.net/qq_45531729/article/details/111680807