Leetcode题解-算法-二分法

1、求开方

69. Sqrt(x)(Easy)
Implement int sqrt(int x).Compute and return the square root of x, where x is guaranteed to be a non-negative integer.

Since the return type is an integer, the decimal digits are truncated and only the integer part of the result is returned.

Example 1:

Input: 4
Output: 2

Example 2:

Input: 8
Output: 2
Explanation: The square root of 8 is 2.82842…, and since the decimal part is truncated, 2 is returned.

class Solution {
public:
    int mySqrt(int x) {
        if(x<1)
            return x;
        int low=1,high=x;
        while(high>=low)
        {
            int mid=low+(high-low)/2;
            int tmp=x/mid;
            if(tmp==mid)
                return mid;
            else if(tmp>mid)
                low=mid+1;
            else
                high=mid-1;
        }
        return high;
    }
};

2、找大于给定字符的最小字符

744. Find Smallest Letter Greater Than Target(Easy)
Given a list of sorted characters letters containing only lowercase letters, and given a target letter target, find the smallest element in the list that is larger than the given target.

Letters also wrap around. For example, if the target is target = ‘z’ and letters = [‘a’, ‘b’], the answer is ‘a’.

Examples:

Input:
letters = [“c”, “f”, “j”]
target = “a”
Output: “c”

Input:
letters = [“c”, “f”, “j”]
target = “c”
Output: “f”

Input:
letters = [“c”, “f”, “j”]
target = “d”
Output: “f”

Input:
letters = [“c”, “f”, “j”]
target = “g”
Output: “j”

Input:
letters = [“c”, “f”, “j”]
target = “j”
Output: “c”

Input:
letters = [“c”, “f”, “j”]
target = “k”
Output: “c”

Note:

  1. letters has a length in range [2, 10000].
  2. letters consists of lowercase letters, and contains at least 2 unique letters.
  3. target is a lowercase letter.

问题分析:
该实现和正常实现有以下不同:

  • 循环条件为 low < high
  • high 的赋值表达式为 high = mid
  • 最后返回 letters[low]

在 target < letters[mid] 的情况下,可以推导出最左 target 位于 [low, mid] 区间中,这是一个闭区间。high 的赋值表达式为 high = mid,因为 mid 位置也可能是解。
在 target >= letters[mid] 的情况下,解的区间为 [mid+1,high]

class Solution {
public:
    char nextGreatestLetter(vector<char>& letters, char target) {
        int low=0,high=letters.size()-1;
        if(target>=letters[high])
            return letters[0];
        while(low<high)
        {
            int mid=low+(high-low)/2;
            if(letters[mid]>target)
                high=mid;
            else
                low=mid+1;
        }
        return letters[low];
    }
};

3、排序重复数组中找出现一次的数

540. Single Element in a Sorted Array(Medium)
Given a sorted array consisting of only integers where every element appears twice except for one element which appears once. Find this single element that appears only once.

Example 1:

Input: [1,1,2,3,3,4,4,8,8]
Output: 2

Example 2:

Input: [3,3,7,7,10,11,11]
Output: 10

Note: Your solution should run in O(log n) time and O(1) space.

排序数组中每个元素出现两次,只有一个元素出现一次。 找到这个出现一次的元素。

问题分析
二分法,每次让 mid 位于序号为偶数的元素上。
如果目标元素在 mid 右边,一定有 nums[mid]==nums[mid+1],目标元素范围更新为 [mid+2,right];
如果目标元素为 mid 或者在 mid 左边,一定有 nums[mid]!=nums[mid+1],目标元素范围更新为 [left,mid]。

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

4、第一个出错的版本

278. First Bad Version(Easy)
给定 n 表示有 n 个版本,如果一个版本出错,后面所有的版本都会出错,找出第一个出错的版本。可以调用 isBadVersion(int x) 知道某个版本是否错误。

Example:

Given n = 5, and version = 4 is the first bad version.
call isBadVersion(3) -> false
call isBadVersion(5) -> true
call isBadVersion(4) -> true
Then 4 is the first bad version.

二分法,如果版本 mid 出错,则第一个错误版本位于区间 [left,mid] 中;
如果版本 mid 未出错,则第一个错误版本位于区间 [mid+1,right] 中。

// Forward declaration of isBadVersion API.
bool isBadVersion(int version);

class Solution {
public:
    int firstBadVersion(int n) {
        int left=0,right=n;
        while(right>left)
        {
            int mid=left+(right-left)/2;
            if(isBadVersion(mid))
                right=mid;
            else
                left=mid+1;
        }
        return left;
    }
};

5、旋转数组最小值

153. Find Minimum in Rotated Sorted Array(Medium)
Suppose an array sorted in ascending order is rotated at some pivot unknown to you beforehand.
(i.e., [0,1,2,4,5,6,7] might become [4,5,6,7,0,1,2]).Find the minimum element.You may assume no duplicate exists in the array.

Example 1:

Input: [3,4,5,1,2]
Output: 1

Example 2:

Input: [4,5,6,7,0,1,2]
Output: 0

问题分析
旋转之后,右侧的数据一定小于左侧的数据,如果 nums[mid]>nums[right],则最小值在 mid 右侧,新的区间更新为 [mid+1,right], nums[mid]<nums[right],则最小值在 mid 及 mid 左侧,区间更新为 [left,mid]。
在这里插入图片描述

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

6、目标数在排序数组中出现的首尾位置

34. Find First and Last Position of Element in Sorted Array(Medium)
Given an array of integers nums sorted in ascending order, find the starting and ending position of a given target value.

Your algorithm’s runtime complexity must be in the order of O(log n).

If the target is not found in the array, return [-1, -1].

Example 1:

Input: nums = [5,7,7,8,8,10], target = 8
Output: [3,4]

Example 2:

Input: nums = [5,7,7,8,8,10], target = 6
Output: [-1,-1]

问题分析:
用二分找到出现目标的最左侧的位置,然后累加找右侧的位置,累加时注意不要越界。

class Solution {
public:
    vector<int> searchRange(vector<int>& nums, int target) {
        vector<int>res(2,-1);
        if(nums.size()==0)
            return res;
        int left=BinarySearch(nums, target);
        if(nums[left]!=target)//目标没有出现
            return res;
        res[0]=left;
        int tmp=left+1;
        while(tmp<nums.size()&&nums[tmp]==nums[left])//不能越界访问
            tmp++;
        res[1]=tmp-1;
        return res;
    }
    int BinarySearch(vector<int>& nums, int target)//二分找到出现目标数最左侧的位置
    {
        int left=0,right=nums.size()-1;
        int mid;
        while(right>left)
        {
            mid=left+(right-left)/2;
            if(nums[mid]>=target)
                right=mid;
            else
                left=mid+1;
        }
        return left;
    }
};
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值