1. Search Insert Position

 class Solution {
public:
int searchInsert(int A[], int n, int target) {
int left=,right=n-;
while(left<=right)
{
int mid=left+(right-left)/;
if(A[mid]==target) return mid;
if(A[mid]<target)
left=mid+;
else right=mid-;
}
return left;
}
};

当循环结束时,如果没有找到目标元素,那么left一定停在恰好比目标大的元素的index上,right一定停在恰好比目标小的index上.

特殊点的例子:当在{1,2,3,4,5}里执行二分查找找0时,此时的left=0, right=-1.(left和right也是挺拼的,为了比target大/小,不惜越界。)

这个规律非常有用,合理利用left和right在未找到target的情况下退出while循环时的特性,能解决很多问题,尤其体现在实现upperBound和lowerBound函数时。如果要利用left或right,需要保证target不在当前区间内,这样才能让while循环以未找到target的状态退出。为了实现这一点,我们需要在即使发现target==A[mid]的情况下仍然假装没看见,继续缩小搜索范围。

因此如果要在二分搜索的基础上计算bound的话,其实就是怎么处理那几个值为target的元素的问题。也就是是否把这部分值恰好为target的元素纳入下一轮搜索范围。(二分搜索本质上就是不断缩小搜索范围)。

以upperBound为例。upperBound函数是找[left,right]内第一个大于target的元素下标------所以值为target的元素肯定要排除在搜索范围之外。这样当A[mid]==target时我们仍将其排除在搜索范围外,即让low=mid+1。一直到搜索范围里已经没有值为target的元素了,此时根据二分查找的性质,当区间里没有找到target时,while循环退出后low指向刚好大于target的位置,high指向刚好小于target的位置。所以此时我们返回low即为刚好大于target的位置,即——第一个大于target的位置。

lowerBound同理。lowerBound是寻找[left,right]内第一个值不小于target的元素下标。“不小于”target的不好求,但刚好小于target的那个元素位置比较好求,因为这就是right的返回值。所以我们按照上述思路,在遇到A[mid]==target的情况下仍假装看不见,继续缩小搜索范围,直到当前范围里没有了target,最终循环退出时right就指向值刚好小于target的元素位置。而(right+1)即为不小于target的元素下标。

lowerBound和upperBound的实现代码在下一题代码中。

What if there are duplicates?

2. Search for a Range

 class Solution {
public:
vector<int> searchRange(int A[], int n, int target) {
int left=,right=n-;
vector<int> res(,-);//[-1,-1]是默认值
while(left<=right)
{
int mid=left+(right-left)/;
if(A[mid]<target)
left=mid+;
else if(A[mid]>target)
right=mid-;
else
{
res[]=lowerBound(A,left,mid,target);
res[]=upperBound(A,mid,right,target)-;//别忘了减1
return res;
}
}
return res;//这一句别忘了。当查找失败时返回[-1,-1].
}
private:
int upperBound(int A[], int left, int right, int target)
{
int low = left, high = right;
while (low <= high)
{
int mid = low + (high - low) / ;
if (A[mid] <= target)
low = mid + ;
else
high = mid - ;
}
return low;
}
int lowerBound(int A[], int left, int right, int target)
{
int low = left, high = right;
while (low <= high)
{
int mid = low + (high - low) / ;
if (A[mid] >= target)
high = mid - ;
else
low = mid + ;
}
return high + ;
}
};

lowerBound和upperBound与binarySearch之间的关系上一题里已经分析过了。

注意几个小细节,已在注释中标明。细节决定成败,bug-free需要谨小慎微。

3. Search in Rotated Sorted Array

 class Solution {
public:
int search(int A[], int n, int target) {
int left=,right=n-;
while(left<=right)
{
int mid=left+(right-left)/;
if(A[mid]==target) return mid;
if(A[mid]<A[right])//说明右半段是有序的
{
if(target>A[mid]&&target<=A[right])
left=mid+;
else
right=mid-;
}
else
{
if(target>=A[left]&&target<A[mid])
right=mid-;
else
left=mid+;
}
}
return -;
}
};

最关键的把握这个规律:"总有一半是有序的,而且和另一半无区间重叠"。code ganker的总结很好。

4. Search in Rotated Sorted Array II

 class Solution {
public:
bool search(int A[], int n, int target) {
for(int i=;i<n;i++)
if(A[i]==target) return true;
return false;
}
};

由于允许有duplicates,会导致没有办法像I中那样根据A[mid]和A[left]、A[right]的比较来确定是哪一半有序,应该在哪一半查找。

导致最坏时间复杂度变为O(n)。因此用最简单的遍历来实现就可以。

5. Search a 2D Matrix

 class Solution {
public:
bool searchMatrix(vector<vector<int> > &matrix, int target) {
if(matrix.size()==||matrix[].size()==) return false;
int m=matrix.size(); int n=matrix[].size();
int left=,right=m*n-;
while(left<=right)
{
int mid=left+(right-left)/;
int midX=mid/n; int midY=mid%n;//注意:这里是n,不是m!
if(matrix[midX][midY]==target) return true;
if(matrix[midX][midY]<target)
left=mid+;
else
right=mid-;
}
return false;
}
};

6. sqrt(x)

  class Solution {
public:
int sqrt(int x) {
if(x<) return x;
int left=,right=x/+;
while(left<=right)
{
int mid=left+(right-left)/;
if(mid<=x/mid&&(mid+)>x/(mid+))//防止溢出
return mid;
if(mid>x/(mid))
right=mid-;
else
left=mid+;
}
return -;
}
};

比较蹊跷的是if(mid>x/mid)和下面的else不能换位置。尚不知为何。

leetcode Ch1-search 2014的更多相关文章

  1. [LeetCode] 034. Search for a Range (Medium) (C++/Java)

    索引:[LeetCode] Leetcode 题解索引 (C++/Java/Python/Sql) Github: https://github.com/illuz/leetcode 035. Sea ...

  2. [LeetCode] 033. Search in Rotated Sorted Array (Hard) (C++)

    指数:[LeetCode] Leetcode 解决问题的指数 (C++/Java/Python/Sql) Github: https://github.com/illuz/leetcode 033. ...

  3. [array] leetcode - 35. Search Insert Position - Easy

    leetcode - 35. Search Insert Position - Easy descrition Given a sorted array and a target value, ret ...

  4. [array] leetcode - 34. Search for a Range - Medium

    leetcode - 34. Search for a Range - Medium descrition Given an array of integers sorted in ascending ...

  5. [array] leetcode - 33. Search in Rotated Sorted Array - Medium

    leetcode - 33. Search in Rotated Sorted Array - Medium descrition Suppose an array sorted in ascendi ...

  6. LeetCode 81 Search in Rotated Sorted Array II [binary search] <c++>

    LeetCode 81 Search in Rotated Sorted Array II [binary search] <c++> 给出排序好的一维有重复元素的数组,随机取一个位置断开 ...

  7. LeetCode 33 Search in Rotated Sorted Array [binary search] <c++>

    LeetCode 33 Search in Rotated Sorted Array [binary search] <c++> 给出排序好的一维无重复元素的数组,随机取一个位置断开,把前 ...

  8. [LeetCode] Binary Search 二分搜索法

    Given a sorted (in ascending order) integer array nums of n elements and a target value, write a fun ...

  9. [leetcode]81. Search in Rotated Sorted Array II旋转过有序数组里找目标值II(有重)

    This is a follow up problem to Search in Rotated Sorted Array, where nums may contain duplicates. 思路 ...

  10. Java for LeetCode 081 Search in Rotated Sorted Array II

    Follow up for "Search in Rotated Sorted Array": What if duplicates are allowed? Would this ...

随机推荐

  1. 深刻理解Python中的元类(metaclass)(转)

    转载地址:http://blog.jobbole.com/21351/ 另外有几点理解记录下: 创建一个实例时,有时会传入参数,这些参数会同时传入 __init__() 和 __new__(),如: ...

  2. Vue触发input选取文件点击事件

    CSS .upload-btn-box { margin-bottom: 10px; button { margin-right: 10px; } input[type=file] { display ...

  3. 2019年UX设计新趋势

    UX设计总是在不断变化中.最近短短两年的时间里,我们已经看到,很多地方都大规模采用颠覆性技术,比如语音用户界面,混合现实和智能家居设备.设计这些体验的实际过程可能保持不变,但新技术的出现引发了新的行为 ...

  4. Python与C相互调用、编译

    因为最近学习Boost::python的缘故,想尝试下不同语言之间的相互编译. 参考资料:http://blog.csdn.net/joliny/article/details/2457197. 很吃 ...

  5. unittest实现批量处理测试集

    批量执行测试集 #coding=utf-8 from selenium import webdriver from selenium.webdriver.common.by import By fro ...

  6. 前端emmet插件的一些常用用法

    以下是在webstorm中简单使用emmet插件,注意一点就是当编写完emmet命令后一定要把光标移动到命令的结尾处,不然生成的代码会不一样 <!DOCTYPE html> <htm ...

  7. 4、在Shell程序中的使用变量

    学习目标变量的赋值变量的访问变量的输入 12-4-1 变量的赋值在Shell编程中,所有的变量名都由字符串组成,并且不需要对变量进行声明.要赋值给一个变量,其格式如下:变量名=值.注意:等号(=)前后 ...

  8. 快手、抖音、微视类短视频SDK接入教程,7步就能搞定

    欢迎大家前往腾讯云+社区,获取更多腾讯海量技术实践干货哦~ 本文由视频咖 发表于云+社区专栏 终端部分 按照如下三步操作,可以用 XCode 或者 Android Studio 编译和调试小视频 Ap ...

  9. 入门系列之在Nginx配置Gzip

    欢迎大家前往腾讯云+社区,获取更多腾讯海量技术实践干货哦~ 本文由小铁匠米兰的v 发表于云+社区专栏 简介 网站加载的速度取决于浏览器必须下载的所有文件的大小.减少要传输的文件的大小可以使网站不仅加载 ...

  10. 事务的编写规范与Hibernate绑定session

    一.事务的编写规范 1.事务的基本概念: 数据库事务(Database Transaction) ,是指作为单个逻辑工作单元执行的一系列操作,要么完全地执行,要么完全地不执行. 事务处理可以确保除非事 ...