leetcode刷题记录——二分查找(入门)

leetcode刷题记录——二分查找(入门)

——参考代码随想录和力扣顺序刷题(https://programmercarl.com/)


题目目录

  35. 搜索插入位置

  69. x 的平方根

  441. 排列硬币

  744. 寻找比目标字母大的最小字母

  278. 第一个错误的版本

  852. 山脉数组的峰顶索引

  367. 有效的完全平方数

  1385. 两个数组间的距离值

  167. 两数之和 II - 输入有序数组

  74. 搜索二维矩阵

  350. 两个数组的交集 II

  633. 平方数之和

  1855. 下标对中的最大距离

  33. 搜索旋转排序数组

  153. 寻找旋转排序数组中的最小值

1、二分查找

  • 版本一
// 版本一
class Solution {
public:
    int search(vector<int>& nums, int target) {
        int left = 0;
        int right = nums.size(); // 定义target在左闭右开的区间里,即:[left, right)
        while (left < right) { // 因为left==right的时候,在[left, right)是无效的空间,所以使用 <
            int middle = left + ((right - left) >> 1);
            if (nums[middle] > target) {
                right = middle; // target 在左区间,在[left, middle)中
            } else if (nums[middle] < target) {
                left = middle + 1; // target 在右区间,在[middle + 1, right)中
            } else { // nums[middle] == target
                return middle; // 数组中找到目标值,直接返回下标
            }
        }
        // 未找到目标值
        return -1;
    }
};
  • 版本二(一般用来求数组下标且不想开新变量)
// 版本一
class Solution {
public:
    int search(vector<int>& nums, int target) {
        int left = 0;
        int right = nums.size() - 1; // 定义target在左闭右闭的区间里,[left, right]
        while (left <= right) { // 当left==right,区间[left, right]依然有效,所以用 <=
            int middle = left + ((right - left) / 2);// 防止溢出 等同于(left + right)/2
            if (nums[middle] > target) {
                right = middle - 1; // target 在左区间,所以[left, middle - 1]
            } else if (nums[middle] < target) {
                left = middle + 1; // target 在右区间,所以[middle + 1, right]
            } else { // nums[middle] == target
                return middle; // 数组中找到目标值,直接返回下标
            }
        }
        // 未找到目标值
        return -1;
    }
};
35. 搜索插入位置(简单)
  • 体会:找临界;找中间位置的第一个比什么什么大的值;找第一个突变的值
69. x 的平方根 (简单)
  • 本质:搜索插入位置

  • 问题 3:为什么有一些二分查找取 mid 的时候,括号里要加 1?

    这是因为 int mid = (left + right) / 2 在区间里有偶数个元素的时候,mid 只能取到位于左边的中间数,要想取到位于右边的中间数,就需要在括号里加 1。

    为什么要取右边中间数呢?这是因为在区间里 只有 22 个元素的时候,把 [left…right] 划分成 [left…mid - 1] 和 [mid…right] 这两个区间,int mid = (left + right) / 2 这种取法不能把搜索区间缩小。

    理解这件事情最典型的例子是「力扣」第 69 题,详细的分析和调试在 这里。

    总之就是为了:避免死循环。

  • 思路:

    • 如果这个整数的平方 恰好等于输入整数,那么我们就找到了这个整数;
    • 如果这个整数的平方 严格大于 输入整数,那么这个整数肯定不是我们要找的那个数;
    • 如果这个整数的平方 严格小于 输入整数,那么这个整数 可能 是我们要找的那个数(重点理解这句话)。

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

441. 排列硬币(简单)
  • 公式:(1+k)k = 2n

  • 本质还是找插入位置(找第一个比2n大的k)相当于返回left - 1(=right)的位置(因为数组索引和值相同,所以位置和值相同)

  • 代码:(为什么=要放在 < 这一个条件里面?)

  • 解释:因为若k小于2n,则需要在left = middle + 1范围里面找,若k + 1大于2n,则返回的结果是k,因此right没有发生变化,只有left发生变化,所以要放在left(<)条件里面;结束时,left的位置一定是第一个比2n大的k的位置,又因为最后结束一定是right = middle - 1或left = middle + 1 且上一次right = left = middle ,所以right一定等于left - 1;

  • 根本原因:加入 = 条件,right就不能改变;

class Solution {
public:
    int arrangeCoins(int n) {
        int left = 1;
        int right = n;
        while(left <= right) {
            int middle = left + (right - left)/2;
            if ((long long) middle * (middle + 1) <= (long long) 2 * n) {
                left = middle + 1;
            }
            else {
                right = middle - 1;
            }
        }
        return right;
    }
};
744. 寻找比目标字母大的最小字母(简单)
  • 本质:搜索插入位置后按照循环队列返回值
278. 第一个错误的版本(简单)
  • 本质:搜索插入位置

给定一个排序数组和一个目标值,在数组中找到目标值,并返回其索引。如果目标值不存在于数组中,返回它将会被按顺序插入的位置。

请必须使用时间复杂度为 O(log n) 的算法。

来源:力扣(LeetCode)
链接:https://leetcode.cn/problems/search-insert-position
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

示例 1:
输入: nums = [1,3,5,6], target = 5
输出: 2

示例 2:
输入: nums = [1,3,5,6], target = 2
输出: 1

示例 3:
输入: nums = [1,3,5,6], target = 7
输出: 4

思路:

  • 二分搜索(思考为什么找不到则返回left)

  • 理解(不考虑nums[0]>target或nums[nums.size()-1]<target):循环结束临界条件为 left == right 退出条件为 left(middle + 1) > right 或者 right(middle - 1) > left

① 当 left(middle + 1) > right时,表示 nums[middle] < target,所以target大于左边的所有数并且大于当前位置的数,当前位置(middle + 1)= left 即插入位置。

② 当 right(middle - 1) > left时,表示nums[middle] > target,所以target小于右边的所有数并且小于当前位置的数,当前位置 left 即为插入位置。

代码:

class Solution {
public:
    int searchInsert(vector<int>& nums, int target) {
        int left = 0;
        int right = nums.size()-1;
        int middle;
        while (left <= right) {
            middle = left + (right - left)/2; //防止溢出
            if(nums[middle] < target) {
                left = middle + 1;
            }
            else if (nums[middle] > target) {
                right = middle -1;
            }
            else if (nums[middle] == target) {
                return middle;
            }
        }
        return left;
    }
};
852. 山脉数组的峰顶索引(中等)

来源:力扣(LeetCode)
链接:https://leetcode.cn/problems/valid-perfect-square
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

思路:

  • 找到那个arr[i]>arr[i+1]的数,看递增还是递减的趋势
  • 注意的点:需要注意数组越界的情况,取值注意从(1~n-1)

代码:

class Solution {
public:
    int peakIndexInMountainArray(vector<int>& arr) {
        int left = 1;
        int right = arr.size()-1;
        while(left < right) {
            int middle = left + (right-left)/2;
            if (arr[middle] > arr[middle+1]) {
                right = middle;
            }
            else {
                left = middle + 1;
            }
        }
        return left;
    }
};
367. 有效的完全平方数(简单)

给定一个 正整数 num ,编写一个函数,如果 num 是一个完全平方数,则返回 true ,否则返回 false 。

(进阶:不要使用任何内置的库函数,如 sqrt)

来源:力扣(LeetCode)
链接:https://leetcode.cn/problems/valid-perfect-square
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

思路:

  • 从0~num之间利用二分查找方法进行比较,注意long square = (long)middle * middle;
  • 两个int int型变量相乘结果显示溢出,虽然square已经声明为long long,但是int int的结果先放在int变量中,与前面的变量类型无关。

代码:

class Solution {
public:
    bool isPerfectSquare(int num) {
        int left = 1;
        int right = num;
        while (left <= right) {
            int middle = left + (right - left)/2;
            long square = (long)middle * middle;
            if (square > num) {
                right = middle -1;
            }
            else if (square < num) {
                left = middle + 1;
            }
            else if (square == num) {
                return true;
            }
        }
        return false;
    }
};
1385. 两个数组间的距离值(简单)

给你两个整数数组 arr1 arr2 和一个整数 d ,请你返回两个数组之间的[距离值]。

[距离值] 定义为符合此距离要求的元素数目:对于元素 arr1[i] ,不存在任何元素 arr2[j] 满足 |arr1[i]-arr2[j]| <= d 。

来源:力扣(LeetCode)
链接:https://leetcode.cn/problems/find-the-distance-value-between-two-arrays
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

思路:

  • 利用high和low指针,分别指向符合条件距离的最大值和最小值(绝对值化简);
  • 否则利用二分查找进行搜索;
  • 理解为:对于arr2的距离范围:[min,max];
  • 好处:化简绝对值消除负数正数加减的影响(不用分类讨论);

代码:

class Solution {
public:
    int findTheDistanceValue(vector<int>& arr1, vector<int>& arr2, int d) {
        sort(arr2.begin(), arr2.end());
        int ans = 0;
        for (auto num1 : arr1) {
            int low = num1 - d;
            int high = num1 + d;
            if (!binarySearch(arr2, low, high)) {
                ans++;
            }
        }
        return ans;
    }

    bool binarySearch(vector<int>& arr, int low, int high) {
        int left = 0;
        int right = arr.size() - 1;
        while (left <= right) {
            int mid = left + (right - left) / 2;
            if (arr[mid] >= low && arr[mid] <= high) {
                return true;
            }
            else if (arr[mid] < low) {
                left = mid + 1;
            }
            else if (arr[mid] > high) {
                right = mid - 1;
            }
        }
        return false;
    }
};
167. 两数之和 II - 输入有序数组(中等)

来源:力扣(LeetCode)
链接:https://leetcode.cn/problems/two-sum-ii-input-array-is-sorted
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

示例 1:

输入:numbers = [2,7,11,15], target = 9
输出:[1,2]
解释:2 与 7 之和等于目标数 9 。因此 index1 = 1, index2 = 2 。返回 [1, 2] 。

思路1:

  • 固定一个数,从这个数右边找target - numbers[i],二分查找;

代码:

class Solution {
public:
    vector<int> twoSum(vector<int>& numbers, int target) {
        for(int i=0;i<numbers.size();i++){
            int left = i+1;
            int right = numbers.size()-1;
            int temp = target - numbers[i];
            while(left <= right) {
                int middle = left + (right - left)/2;
                if(temp == numbers[middle]) {
                    return {i+1,middle+1};
                }
                else if(temp > numbers[middle]) {
                    left = middle + 1;
                }
                else {
                    right = middle - 1;
                }
            }
        }
        return {-1,-1};
    }
};

思路2:

  • 双指针,low(指向最低位),high(指向最高位);有点像快排;
class Solution {
public:
    vector<int> twoSum(vector<int>& numbers, int target) {
        int low = 0;
        int high = numbers.size() - 1;
        while(low < high) {
            int sum = numbers[low] + numbers[high];
            if(sum < target) low++;
            else if (sum > target) high--;
            else return {low+1,high+1};
        }
        return {-1,-1};
    }
};
74. 搜索二维矩阵(中等)

编写一个高效的算法来判断 m x n 矩阵中,是否存在一个目标值。该矩阵具有如下特性:

每行中的整数从左到右按升序排列。
每行的第一个整数大于前一行的最后一个整数。

来源:力扣(LeetCode)
链接:https://leetcode.cn/problems/search-a-2d-matrix
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

示例 1:

在这里插入图片描述

输入:matrix = [[1,3,5,7],[10,11,16,20],[23,30,34,60]], target = 3
输出:true

思路1:

  • 从第一行开始递归,用二分查找来找到需要找的值

代码:

class Solution {
public:
    bool searchMatrix(vector<vector<int>>& matrix, int target) {
        int i=0;
        while(i<matrix.size()) {
            int left = 0;
            int right = matrix[i].size() - 1;
            while(left<=right) {
                int middle = left + (right - left)/2;
                if(matrix[i][middle] == target) return true;
                else if (matrix[i][middle] > target) {
                    right = middle - 1;
                }
                else {
                    left = middle + 1;
                }
            }
            i+=1;
        }
        return false;
    }
};

思路2:

  • 将整个矩阵看成一个递增的一维数组
class Solution {
public:
    bool searchMatrix(vector<vector<int>>& matrix, int target) {
        int m = matrix.size();
        int n = matrix[0].size();
        int left = 0;
        int right = m*n -1;
        while(left<=right) {
            int middle = left + (right - left)/2;
            if(matrix[middle/n][middle%n] == target) {
                return true;
            }
            else if(matrix[middle/n][middle%n] > target) {
                right = middle - 1;
            }
            else{
                left = middle + 1;
            }
        }
        return false;
    }
};
350. 两个数组的交集 II(简单)

给你两个整数数组 nums1 和 nums2 ,请你以数组形式返回两数组的交集。返回结果中每个元素出现的次数,应与元素在两个数组中都出现的次数一致(如果出现次数不一致,则考虑取较小值)。可以不考虑输出结果的顺序。

示例 1:
输入:nums1 = [1,2,2,1], nums2 = [2,2]
输出:[2,2]
   
示例 2:
输入:nums1 = [4,9,5], nums2 = [9,4,9,8,4]
输出:[4,9]

思路1:

  • 循环第一个数组,对第二个数组进行二分查找;
class Solution {
public:
    vector<int> intersect(vector<int>& nums1, vector<int>& nums2) {
        sort(nums1.begin(),nums1.end());
        sort(nums2.begin(),nums2.end());
        vector<int> ans;
        int j = 0;
        for(int i=0;i<nums1.size();i++) {
            int flag = 0;
            int left = j;
            int right = nums2.size()-1;
            int middle;
            while(left<=right) {
                middle = left + (right - left)/2;
                if (nums1[i] == nums2[middle]) {
                    flag = 1;
                    j = middle + 1;
                    right = middle - 1;
                }
                else if (nums1[i] > nums2[middle]) {
                    left = middle + 1;
                }
                else {
                    right = middle - 1;
                }
            }
            if(flag) {
                ans.push_back(nums2[left]);
            }
        }
        return ans;
    }
};

思路2:

  • 排序 + 双指针
  • 初始时,两个指针分别指向两个数组的头部。每次比较两个指针指向的两个数组中的数字,如果两个数字不相等,则将指向较小数字的指针右移一位,如果两个数字相等,将该数字添加到答案,并将两个指针都右移一位。当至少有一个指针超出数组范围时,遍历结束。
class Solution {
public:
    vector<int> intersect(vector<int>& nums1, vector<int>& nums2) {
        sort(nums1.begin(),nums1.end());
        sort(nums2.begin(),nums2.end());
        int left = 0;
        int right = 0;
        vector<int> ans;
        while(left < nums1.size() && right < nums2.size()) {
            if(nums1[left] == nums2[right]) {
                ans.push_back(nums2[right]);
                left++;
                right++;
            }
            else if(nums1[left] > nums2[right]) {
                right++;
            }
            else left++;
        }
        return ans;
    }
};

复杂度分析

  • 时间复杂度:O(mlogm+nlogn),其中 mm 和 nn 分别是两个数组的长度。对两个数组进行排序的时间复杂度是 O(mlogm+nlogn),遍历两个数组的时间复杂度是 O(m+n),因此总时间复杂度是 O(mlogm+nlogn)。

来源:力扣(LeetCode)
链接:https://leetcode.cn/problems/intersection-of-two-arrays-ii
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

633. 平方数之和(中等)

给定一个非负整数 c ,你要判断是否存在两个整数 ab,使得 a2 + b2 = c

示例 1:
输入:c = 5
输出:true
解释:1 * 1 + 2 * 2 = 5
    
示例 2:
输入:c = 3
输出:false

思路1:

  • 先固定一个数,再用二分找第二个数(超时)

思路2:

  • 双指针
  • 如下图所示:low = 0 , high = sqrt© 用low²和high²来进行比较
  • 如果low² + high² < c =》 low++
  • 如果low² + high² > c =》 high--
    • 解释:对角线相当于low² + high²的值,low++相当于让格子向下移动,覆盖整一行, high--相当于格子左移动,在这一行上进行移动,而整个表格从上到下从左到右都是递增的,因此可以找到目标c;

在这里插入图片描述

作者:ggt55ng6
链接:https://leetcode.cn/problems/sum-of-square-numbers/solution/shuang-zhi-zhen-de-ben-zhi-er-wei-ju-zhe-ebn3/

代码:

class Solution {
public:
    bool judgeSquareSum(int c) {
        int low = 0;
        int high = sqrt(c);
        while(low<=high) {
            long long sum = (long long) low*low + (long long) high*high;
            if(sum == c) return true;
            else if(sum > c) high--;
            else if(sum < c) low++;
        }
        return false;
    }
};

来源:力扣(LeetCode)
链接:https://leetcode.cn/problems/sum-of-square-numbers/
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处

1855. 下标对中的最大距离(中等)

给你两个 非递增 的整数数组 nums1 和 nums2 ,数组下标均 从 0 开始 计数。下标对 (i, j) 中 0 <= i < nums1.length 且 0 <= j < nums2.length 。如果该下标对同时满足 i <= j 且 nums1[i] <= nums2[j] ,则称之为 有效 下标对,该下标对的 距离 为 j - i 。返回所有 有效 下标对 (i, j) 中的 最大距离 。如果不存在有效下标对,返回 0 。一个数组 arr ,如果每个 1 <= i < arr.length 均有 arr[i-1] >= arr[i] 成立,那么该数组是一个 非递增 数组。

示例 1:
输入:nums1 = [55,30,5,4,2], nums2 = [100,20,10,10,5]
输出:2
解释:有效下标对是 (0,0), (2,2), (2,3), (2,4), (3,3), (3,4) 和 (4,4) 。
最大距离是 2 ,对应下标对 (2,4) 。
    
示例 2:
输入:nums1 = [2,2,2], nums2 = [10,10,1]
输出:1
解释:有效下标对是 (0,0), (0,1) 和 (1,1) 。
最大距离是 1 ,对应下标对 (0,1) 。
    
示例 3:
输入:nums1 = [30,29,19,5], nums2 = [25,25,25,25,25]
输出:2
解释:有效下标对是 (2,2), (2,3), (2,4), (3,3) 和 (3,4) 。
最大距离是 2 ,对应下标对 (2,4) 。

思路1:

  • 固定一个数组的值,对第二个数组进行二分查找
class Solution {
public:
    int maxDistance(vector<int>& nums1, vector<int>& nums2) {
        int maxd = 0;
        for(int i=0;i<nums1.size();i++) {
            int left = i;
            int right = nums2.size()-1;
            while(left<=right) {
                int middle = left + (right - left)/2;
                if(nums2[middle] >= nums1[i]) {
                    if(middle - i > maxd) maxd = middle - i;
                    left = middle + 1;
                }
                else right = middle - 1;
            }
        }
        return maxd;
    }
};

思路2:

  • 双指针
  • 定义p1,p2 如果nums1[p1] > nums2[p2],则没有距离,p1p2都要加1(递减且保证p1<=p2)就不会出现:if(left > right) right = left;(自己的步骤)
  • 如果p1 != p2 则一定是p1<p2
class Solution {
   public int maxDistance(int[] nums1, int[] nums2) {
        int p1 = 0;
        int p2 = 0;
        int res = 0;
        while (p1 < nums1.length && p2 <nums2.length){
            if(nums1[p1] > nums2[p2]){  //无效
                if(p1 == p2){
                    p1++;
                    p2++;
                }else p1++;
            }else {     //有效
                res =Math.max(res,p2-p1);
                p2++;
            }
        }
        return res;
    }
}

//作者:SweetTea
//链接:https://leetcode.cn/problems/maximum-distance-between-a-pair-of-values/solution/java-jing-dian-shuang-zhi-zhen-by-sweett-z06l/
//来源:力扣(LeetCode)
//著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

//自己的做法:
class Solution {
public:
    int maxDistance(vector<int>& nums1, vector<int>& nums2) {
        int left = 0;
        int right = 0;
        int maxd = 0;
        while(left < nums1.size() && right < nums2.size()) {
            if(left > right) right = left;//可以不出现
            if(nums1[left] <= nums2[right]) {
                if(right - left >= maxd) maxd = right - left;
                right++;
            }
            else if(nums1[left] > nums2[right]) {
                left++;
                //right++;
            }
        }
        return maxd;
    }
};

复杂度分析

  • O(n1+n2)最多遍历两个数组各一次。

来源:力扣(LeetCode)
链接:https://leetcode.cn/problems/maximum-distance-between-a-pair-of-values
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

33. 搜索旋转排序数组(中等)

整数数组 nums 按升序排列,数组中的值 互不相同 。

在传递给函数之前,nums 在预先未知的某个下标 k(0 <= k < nums.length)上进行了 旋转,使数组变为 [nums[k], nums[k+1], …, nums[n-1], nums[0], nums[1], …, nums[k-1]](下标 从 0 开始 计数)。例如, [0,1,2,4,5,6,7] 在下标 3 处经旋转后可能变为 [4,5,6,7,0,1,2] 。

给你 旋转后 的数组 nums 和一个整数 target ,如果 nums 中存在这个目标值 target ,则返回它的下标,否则返回 -1 。

你必须设计一个时间复杂度为 O(log n) 的算法解决此问题。

示例 1:
输入:nums = [4,5,6,7,0,1,2], target = 0
输出:4
   
示例 2:
输入:nums = [4,5,6,7,0,1,2], target = 3
输出:-1
   
示例 3:
输入:nums = [1], target = 0
输出:-1

提示:

  • 1 <= nums.length <= 5000
  • -10000 <= nums[i] <= 10000
  • nums 中的每个值都 独一无二
  • 题目数据保证 nums 在预先未知的某个下标上进行了旋转
  • -10000 <= target <= 10000

思路:

  • 找到合适的区间 进行合适的分区来用二分;
  • 和nums[0]进行比较,如果nums[middle] > nums[0] 则说明:在 0 - middle 区间内,是有序的,递增的;旋转点在middle - nums.size()-1 之间(nums[0] > nums[nums.size()-1])
  • 进行分区:有序的,无序的
    • nums[middle] >= nums[0] 有序:target在0 - middle之间二分查找
    • nums[middle] >= nums[0] 无序:target在middle - nums.size()-1之间二分查找
    • (nums[middle] < nums[0] 同理)
    • 无序的一边可以理解为一个新的旋转数组

代码:

class Solution {
public:
    int search(vector<int>& nums, int target) {
        if (nums.size() == 0) return -1;
        if (nums.size() == 1) return nums[0] == target ? 0 : -1;
        int left = 0;
        int right = nums.size() - 1;
        while(left <= right) {
            int middle = left + (right - left)/2;
            if(nums[middle] == target) return middle;
            if(nums[middle] >= nums[left]) {
                if(nums[left] <= target && target < nums[middle]) right = middle - 1;
                else left = middle + 1;
            }
            else if (nums[middle] < nums[right]) {
                if(nums[middle] < target && target <= nums[right]) left = middle + 1;
                else right = middle - 1;
            }
        }
        return -1;
    }
};

复杂度分析

  • 二分查找时间复杂度:O(logn)

来源:力扣(LeetCode)
链接:https://leetcode.cn/problems/search-in-rotated-sorted-array
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

153. 寻找旋转排序数组中的最小值(中等)

已知一个长度为 n 的数组,预先按照升序排列,经由 1 到 n 次 旋转 后,得到输入数组。例如,原数组 nums = [0,1,2,4,5,6,7] 在变化后可能得到:
若旋转 4 次,则可以得到 [4,5,6,7,0,1,2]
若旋转 7 次,则可以得到 [0,1,2,4,5,6,7]
注意,数组 [a[0], a[1], a[2], …, a[n-1]] 旋转一次 的结果为数组 [a[n-1], a[0], a[1], a[2], …, a[n-2]] 。

给你一个元素值 互不相同 的数组 nums ,它原来是一个升序排列的数组,并按上述情形进行了多次旋转。请你找出并返回数组中的 最小元素 。

你必须设计一个时间复杂度为 O(log n) 的算法解决此问题。

示例 1:
输入:nums = [3,4,5,1,2]
输出:1
解释:原数组为 [1,2,3,4,5] ,旋转 3 次得到输入数组。
    
示例 2:
输入:nums = [4,5,6,7,0,1,2]
输出:0
解释:原数组为 [0,1,2,4,5,6,7] ,旋转 4 次得到输入数组。
    
示例 3:
输入:nums = [11,13,15,17]
输出:11
解释:原数组为 [11,13,15,17] ,旋转 4 次得到输入数组。

提示:

  • n == nums.length
  • 1 <= n <= 5000
  • -5000 <= nums[i] <= 5000
  • nums 中的所有整数 互不相同
  • nums 原来是一个升序排序的数组,并进行了 1 至 n 次旋转

思路:

  • 和nums[0]进行比较,如果nums[middle] > nums[0] 则说明:在 0 - middle 区间内,是有序的,递增的;(每次只旋转一个)
  • 然后进行局部最小值查找(简单)

代码:

class Solution {
public:
    int findMin(vector<int>& nums) {
        if(nums.size() == 1) return nums[0] ;
        int min = 5001;
        int left = 0;
        int right = nums.size() - 1;
        while(left <= right) {
            int middle = left + (right - left)/2;
            if(nums[middle] >= nums[0]) {
                if(nums[0] < min) {
                    min = nums[0];
                }
                left = middle + 1;
            }
            else if(nums[middle] < nums[0]) {
                if(nums[middle] < min) {
                    min = nums[middle];
                }
                right = middle - 1;
            }
        }
        return min;
    }
};

复杂度分析

  • 二分查找时间复杂度:O(logn)

来源:力扣(LeetCode)
链接:https://leetcode.cn/problems/find-minimum-in-rotated-sorted-array
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值