一、 Binary Search

 int binarySearch(vector<int> &array, int target)
{
int lo = , hi = array.size() - ;
while (lo <= hi)
{
int mid = lo + (hi - lo) / ;
if (array[mid] > target)
hi = mid - ;
else if (array[mid] < target)
lo = mid + ;
else return mid;
}
return -;
}

注意是 while(lo<=hi)

当然,也不是绝对的,这只是我的习惯写法。while里是 还是 <= 取决于hi/right 的初值和赋值。

/首先要把握下面几个要点:
//right=n-1 => while(left <= right) => right=middle-1;
//
right=n => while(left < right) => right=middle;

ref to july

二、 Search Insert Position

 class Solution
{
public:
int searchInsert(vector<int> &nums,int target)
{
int lo=,hi=nums.size()-;
while(lo<=hi)
{
int mid=lo+(hi-lo)/;
if(nums[mid]>target)
hi=mid-;
else if(nums[mid]<target)
lo=mid+;
else return mid;
}
return lo;
}
};

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

【简单理解的话,因为如果找不到目标元素,那么退出循环时必定是lo>hi的。此时lo指向大于target的元素,hi指向小于target的元素】

详细查看自己以前写的分析: ref

三、

1. Search for a Range

 class Solution
{
public:
vector<int> searchRange(vector<int> &nums,int target)
{
vector<int> res(,-);
int lo=,hi=nums.size()-;
while(lo<=hi)
{
int mid=lo+(hi-lo)/;
if(nums[mid]>target)
hi=mid-;
else if(nums[mid]<target)
lo=mid+;
else
{
res[]=lowerbound(nums,lo,mid,target);
res[]=upperbound(nums,mid,hi,target)-;
return res; //千万别遗漏
}
}
return res;
}
int upperbound(vector<int> &nums,int left,int right,int target)
{
int lo=left,hi=right;
while(lo<=hi)
{
int mid=lo+(hi-lo)/;
if(nums[mid]>target)
hi=mid-;
else if(nums[mid]<=target)
lo=mid+;
}
return lo;
}
int lowerbound(vector<int> &nums,int left,int right,int target)
{
int lo=left,hi=right;
while(lo<=hi)
{
int mid=lo+(hi-lo)/;
if(nums[mid]>=target)
hi=mid-;
else if(nums[mid]<target)
lo=mid+;
}
return hi+;
}
};

注意Line17,18处,范围分别缩小成(lo,mid)和(mid,hi)了。

upperbound和lowerbound的原理详见以前的分析,第1题后面那一大段总结。

#2: upperBound返回的是第一个大于target元素的位置;lowerBound返回的是第一个小于等于target元素的位置。

所以对于一个nums中有的元素,返回其range应该是 [lowerBound, upperBound - 1]

另外,还有一点需要特别注意:Line19千万不能遗漏,如果遗漏了就成了TLE。

update 15.8.21

上述的upperBound和lowerBound中的“大于”,“小于等于”是库函数里的定义。我可以不用管那么多,就分别用lowerBound和upperBound分别返回target在数组中的第一个和最后一个的位置即可。清晰自然。

 vector<int> searchRange(vector<int>& nums, int target) {
vector<int> result(, -);
int lo = , hi = nums.size() - ;
while (lo <= hi) {
int mid = lo + (hi - lo) / ;
if (nums[mid] < target) {
lo = mid + ;
} else if (nums[mid] > target) {
hi = mid - ;
} else {
result[] = lowerBound(nums, target);
result[] = upperBound(nums, target);
return result;
}
}
return result;
} int upperBound(vector<int>& nums, int target) {
int lo = , hi = nums.size() - ;
while (lo <= hi) {
int mid = lo + (hi - lo) / ;
if (nums[mid] <= target) {
lo = mid + ;
} else {
hi = mid - ;
}
}
return lo - ;
}
int lowerBound(vector<int>& nums, int target) {
int lo = , hi = nums.size() - ;
while (lo <= hi) {
int mid = lo + (hi - lo) / ;
if (nums[mid] < target) {
lo = mid + ;
} else {
hi = mid - ;
}
}
return hi + ;
}

在upperBound函数里,当nums[mid] == target时就当没看到,继续把lo向右移动。因此当退出while循环时,lo所指向的就是最后一个元素的位置+1处。返回lo - 1即为最后一个target的位置;

同理,lowerBound里,当nums[mid] == target时就当没看到,继续把hi向左移动。因此当退出while循环时,hi所指向的就是第一个元素的位置-1处。返回hi + 1即为第一个target的位置。

2. Binary Search   [lintcode]

 class Solution {
public:
int binarySearch(vector<int> &array, int target) {
int lo=,hi=array.size()-;
while(lo<=hi)
{
int mid=lo+(hi-lo)/;
if(array[mid]>target)
hi=mid-;
else if(array[mid]<target)
lo=mid+;
else
{
return lowerbound(array,lo,mid,target);
}
}
return -;
}
int lowerbound(vector<int> &array,int left,int right,int target)
{
int lo=left,hi=right;
while(lo<=hi)
{
int mid=lo+(hi-lo)/;
if(array[mid]>=target)
hi=mid-;
else lo=mid+;
}
return hi+;
}
};

一开始以为是普通的binary search,后来发现它是要返回第一个target的位置(即有可能有duplicates)。借助lowerbound函数即可。

四、

1. Search in Rotated Sorted Array

O(logN):

 class Solution
{
public:
int search(vector<int> &nums,int target)
{
int lo=,hi=nums.size()-;
while(lo<=hi)
{
int mid=lo+(hi-lo)/;
if(nums[mid]==target) return mid;
if(nums[mid]<nums[hi])//说明右半段有序
{
if(target>nums[mid] && target<=nums[hi])
lo=mid+;
else hi=mid-;
}
else //说明左半段有序
{
if(target<nums[mid] && target>=nums[lo])
hi=mid-;
else lo=mid+;
}
}
return -;
}
};

另一种方法:利用下面3. Find Minimum先把min的index找出来,然后根据target在哪个范围来对其进行binarySearch。

2. Search in Rotated Sorted Array II

 class Solution {
public:
bool search(vector<int>& nums, int target) {
for(int i=;i<nums.size();i++)
if(nums[i]==target) return true;
return false;
}
};

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

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

而普通情况下为O(logN),只在最坏情况下为O(N)的,可参考该问题下第一个答案

3. Find Minimum in Rotated Sorted Array

code 1:

 class Solution {
public:
int findMin(vector<int> &nums) {
int lo = , hi = nums.size() - ;
int target = nums[hi];
while (lo + < hi) {
int mid = lo + (hi - lo) / ;
if (nums[mid] > target) {
lo = mid;
} else {
hi = mid;
}
}
return min(nums[lo], nums[hi]);
}
};

NCH版本的binarySearch。用这种版本的binarySearch的好处是,在lo和hi中必有一个是最终结果,所以只需要在这两个里比较一下即可。而如果用我之前的BinarySearch版本,需要纠结和考虑究竟是返回lo还是hi。

用这种版本的BinarySearch需要注意的地方在于

1. while (lo + 1 < hi)

2. lo = mid; hi = mid;

另外,在退出while循环时,lo在左边,紧接着hi在lo右边,hi = lo + 1。并不是之前那样hi小lo大。

code 2:

 class Solution {
public:
int findMin(vector<int> &nums) {
int lo = , hi = nums.size() - ;
int target = nums[hi];
while (lo <= hi) {
int mid = lo + (hi - lo) / ;
if (nums[mid] > target) {
lo = mid + ;
} else {
hi = mid - ;
}
}
return nums[lo];
}
};

4. Find Minimum in Rotated Sorted Array II

可以直接线性遍历一遍,最坏时间复杂度最快也只能是O(N).

五、

1. Search a 2D Matrix

 class Solution
{
public:
bool searchMatrix(vector<vector<int>> &matrix, int target) {
if(matrix.empty()) return -;
int m = matrix.size(), n = matrix[].size();
int lo = , hi = m * n - ;
while(lo <= hi) {
int mid = lo + (hi - lo) / ;
int x = mid / n;
int y = mid % n;
if (matrix[x][y] < target) {
lo = mid + ;
} else if (matrix[x][y] > target) {
hi = mid - ;
} else return true;
}
return false;
}
};

一开始写的很复杂, 先找行数再找列数,代码长又易出错。后来参考soulmach,将二维问题转化为一维问题,瞬间简洁。

另外,以后要注意coding style了。

2. Search a 2D Matrix II [lintcode]

 class Solution {
public:
int searchMatrix(vector<vector<int> > &matrix, int target) {
if (matrix.empty()) return ;
int count = ;
int m = matrix.size(), n = matrix[].size();
int row = , col = n - ;
while (row < m && col >= ) {
if (matrix[row][col] < target) {
row++;
} else if (matrix[row][col] > target) {
col--;
} else {
count++;
row++; //或者 col--也行
}
}
return count;
}
};

时间复杂度O(m+n).  这也是剑指offer上一道题。思路就是以右上角元素作为起点,向左下方走。每次可以删掉一行或一列。

六、

1. Sqrt(x)

 class Solution
{
public:
int mySqrt(int x) {
if(x < ) return x;
int lo = , hi = x;
while(lo <= hi) {
int mid = lo + ((hi - lo) >> );
if(mid < x / mid) {
lo = mid + ;
} else if (mid > x / mid){
hi = mid - ;
} else return mid;
}
return hi;
}
};

2. Pow(x, n)

 class Solution{
public:
double myPow(double x, int n) {
return (n > ? power(x , n) : 1.0 / power(x , -n));
}
double power(double x, int n) {
if (n == ) return ;
double v = power(x , n / );
if (n % == ) return (v * v * x);
else return (v * v);
}
};

七、

1. First Bad Version [lintcode]

 class Solution {
public:
int findFirstBadVersion(int n) {
int lo = , hi = n;
while (lo + < hi) {
int mid = lo + (hi - lo) / ;
if (VersionControl::isBadVersion(mid) == false) {
lo = mid;
} else {
hi = mid;
}
}
if (VersionControl::isBadVersion(lo) == true) {
return lo;
} else {
return hi;
}
return -;
}
};

2. Find Peak Element

 class Solution {
public:
int findPeakElement(vector<int> &nums) {
int lo = , hi = nums.size() - ;
while (lo + < hi) {
int mid = lo + (hi - lo) / ;
if (nums[mid] < nums[mid - ]) {
hi = mid;
} else if (nums[mid] < nums[mid + ]) {
lo = mid;
} else {// nums[mid] > nums[mid - 1] && nums[mid] > nums[mid + 1]
return mid;
}
}
return nums[lo] < nums[hi] ? hi : lo;
}
};

能进入Line 5的while循环说明至少有3个元素。

八、

1. Remove Duplicates from Sorted Array

 class Solution {
public:
int removeDuplicates(vector<int> &nums) {
if (nums.size() < ) {
return nums.size();
}
int index = ;
for (int i = ; i < nums.size(); i++) {
if (nums[i] != nums[i - ]) {
nums[index++] = nums[i];
}
}
return index;
}
};

2. Remove Duplicates from Sorted Array II

code 1: [推荐]

 class Solution {
public:
int removeDuplicates(vector<int> &nums) {
int n = nums.size();
int k = ;
if (n <= k) {
return n;
}
int index = , cnt = ;
for (int i = ; i < n; i++) {
if (nums[i] != nums[i - ]) {
cnt = ;
nums[index++] = nums[i];
} else {
if (cnt < k) {
cnt++;
nums[index++] = nums[i];
}
}
}
return index;
}
};

该代码是通用版代码。k表示单个元素最多能允许duplicate的个数。将k改为1即可用于上一题。

code 2:

 class Solution {
public:
int removeDuplicates(vector<int> &nums) {
int n = nums.size();
int k = ;
if (n <= k) {
return n;
}
int index = , j = ;
int cnt = ;
while (j < n) {
if (nums[j] != nums[j - ]) {
cnt = ;
nums[index++] = nums[j];
} else {
if (cnt < k) {
nums[index++] = nums[j];
cnt++;
}
}
j++;
}
return index;
}
};

ref

九、 Merge Sorted Array

 class Solution {
public:
void merge(vector<int> &nums1, int m, vector<int> &nums2, int n) {
int i = m - , j = n - , k = m + n - ;
while (i >= && j >= ) {
nums1[k--] = (nums1[i] >= nums2[j] ? nums1[i--] : nums2[j--]);
}
while (j >= ) {
nums1[k--] = nums2[j--];
}
}
};

十、 Median of Two Sorted Arrays

 class Solution {
public:
double findMedianSortedArrays(vector<int> &nums1, vector<int> &nums2) {
int m = nums1.size(), n = nums2.size();
if ((m + n) % == ) {
return findKth(nums1, , m - , nums2, , n - , (m + n) / + );
} else {
return (findKth(nums1, ,m - , nums2, , n - , (m + n) / )
+ findKth(nums1, , m - , nums2, , n - , (m + n) / + )) / 2.0;
}
}
int findKth(vector<int> &nums1, int aL, int aR, vector<int> &nums2, int bL, int bR, int k) {
if (aL > aR) {
return nums2[bL + k - ];
}
if (bL > bR) {
return nums1[aL + k - ];
}
int aMid = (aL + aR) / ;
int bMid = (bL + bR) / ;
if (nums1[aMid] < nums2[bMid]) {
if (k <= (aMid - aL + bMid - bL + )) {
return findKth(nums1, aL, aR, nums2, bL, bMid - , k);
} else {
return findKth(nums1, aMid + , aR, nums2, bL, bR, k - (aMid - aL + ));
}
} else {
if (k <= (aMid - aL + bMid - bL + )) {
return findKth(nums1, aL, aMid - , nums2, bL, bR, k);
} else {
return findKth(nums1, aL, aR, nums2, bMid + , bR, k - (bMid - bL + ));
}
}
}
};

每次取两数组的中间点进行比较。

若A数组的中间点的值 < B数组的中间点的值,则

  如果k很小,则剔除B数组的后半段;( 这里的k很小指的是:k <= (A中点以左的长度 + B中点以左的长度 + 1))

  如果k很大,则剔除A数组的前半段;

同理,若A数组的中间点的值 > B数组的中间点的值,也类似地讨论。

ref 有讲解。

需要注意的点:

Line22 & 28 : 严格一致。

Line 23,25,29,31: 原则就是,当k小时,就去掉较大的数组的较大的半段(后半段);当k大时,就去掉较小的数组的较小的半段(前半段)。

Line21 : <或<=均可。

十一、 三步翻转法:

1. Recover Rotated Sorted Array

 class Solution {
public:
void recoverRotatedSortedArray(vector<int> &nums) {
int i = ;
for (; i < nums.size() - ; i++) {
if (nums[i] > nums[i + ]) {
break;
}
}
reverse(nums, , i);
reverse(nums, i + , nums.size() - );
reverse(nums, , nums.size() - );
}
void reverse(vector<int> &nums, int start, int end) {
while (start < end) {
int tmp = nums[start];
nums[start] = nums[end];
nums[end] = tmp;
start++;
end--;
}
}
};

注意:必须用自己实现的reverse函数,不能用sort,因为sort的时间复杂度是O(nlogn),而题目要求是O(n);

2. Rotate String

 class Solution {
public:
string rotateString(string A, int offset) {
int len = A.length();
if (len <= ) {
return A;
}
offset = offset % len;
reverse(A, , len - - offset);
reverse(A, len - offset, len - );
reverse(A, , len - );
return A;
}
void reverse(string &str, int start, int end) {
while (start < end) {
int tmp = str[start];
str[start] = str[end];
str[end] = tmp;
start++;
end--;
}
}
};

注意小细节:

(1). offset需要取余; (2). 当len == 0 时需要作特殊处理。corner case.

3. Rotate Array

 class Solution {
public:
void rotate(vector<int>& nums, int k) {
k = k % nums.size();
reverse(nums, , nums.size() - - k);
reverse(nums, nums.size() - k, nums.size() - );
reverse(nums, , nums.size() - );
}
void reverse(vector<int> &nums, int start, int end) {
while (start < end) {
int tmp = nums[start];
nums[start] = nums[end];
nums[end] = tmp;
start++;
end--;
}
}
};

和上一题一样。

4. Reverse Words in a String

方法一:空间O(n), 时间O(n)

 class Solution {
public:
void reverseWords(string &s) {
string result;
for (int i = s.size() - ; i >= ;) {
while (i >= && s[i] == ' ') {
i--;
}
if (i < ) {
break;
}
if (!result.empty()) {
result += ' ';
}
string word;
while (i >= && s[i] != ' ') {
word += s[i];
i--;
}
reverse(word.begin(), word.end());
result += word;
}
s = result;
}
};

注意:Line 9 千万不能少,这句代码的意义在于,抛弃开头的那些leading spaces。

ref

方法二:空间O(1) [in-place], 时间O(n).

 class Solution {
public:
void reverseWords(string &s) {
reverse(s, , s.size() - );
int index = ;
for (int i = ; i < s.size(); i++) {
if (s[i] != ' ') {
if (index != ) {
s[index++] = ' ';
}
int j = i;
while (j < s.size() && s[j] != ' ') {
s[index++] = s[j++];
}
reverse(s, index - (j - i), index - );
i = j;
}
}
s.resize(index);
}
void reverse(string &str, int start, int end) {
while (start < end) {
int tmp = str[start];
str[start] = str[end];
str[end] = tmp;
start++;
end--;
}
}
};

ref

5. Reverse Words in a String II

 class Solution {
public:
void reverseWords(string &s) {
reverse(s, , s.size() - );
int index = ;
for (int j = ; j <= s.size(); j++) {
if (j == s.size() || s[j] == ' ') {
reverse(s, index, j - );
index = j + ;
}
}
}
void reverse(string &str, int start, int end) {
while (start < end) {
int tmp = str[start];
str[start] = str[end];
str[end] = tmp;
start++;
end--;
}
}
};

注意:这里让j从0一直循环到s.size(), 原因在于将“遇到空格”和“遇到句末”统一到一个if里,使代码简洁。

题目描述     ref

leetcode Ch1-Search的更多相关文章

  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. 阿里云CentOS7.4上搭建FTP服务器

    1 安装过程 第一步:首先判断是否安装了vsftpd # rpm -qa | grep vsftpd 第二步:如果没有安装则安装vsftpd # yum -y install vsftpd 从第三步开 ...

  2. 《python灰帽子》学习笔记:写一个windos 调试器(一)

    一.开发内容介绍 为了对一个进程进行调试,你首先必须用一些方法把调试器和进程连接起来.所以, 我们的调试器要不然就是装载一个可执行程序然后运行它, 要不然就是动态的附加到一个运行的进程.Windows ...

  3. Hudson-ci/Installing Hudson Windows Service---官方文档

    < Hudson-ci Hudson Continuous Integration Server Website Download Community Mailing List • Forums ...

  4. Visual Studio for Mac 安装无响应或者无法连接网络等解决方法

    1.无法连接到网络 2.点击安装和更新无响 这两种情况造成的原因都是由于被墙的原因,第一种情况有部分可以通过fq解决,第二种情况是我遇到过的 反正我全局也失败 这里给出一个我自己用过的解决方案 查看控 ...

  5. [C语言] 数据结构-衡量算法的标准

    1.衡量算法的标准 算法 解题的方法和步骤 衡量算法的标准 1.时间复杂度 大概程序要执行的次数,而非执行的时间,不同的机器运行时间肯定不一样. 2.空间复杂度 算法执行过程中大概所占用的最大内存 3 ...

  6. [javaSE] GUI(对话框Dialog)

    对话框不能单独存在,依赖于窗体,有显示标题,有模式 获取Dialog对象,new出来,构造参数:Frame对象,String的标题,模式 窗体内部的内容,Label对象,Button对象,调用Dial ...

  7. java中的奇葩 “:”

    一.经常使用java的人有没有发现java也可以将汉字作为标识符出现呢? 在Java语言中,标识符是以字母.下划线(_)或美元符($)开头,由字母.数字.下划线(_)或美元符($)组成的字符串 真的输 ...

  8. 基于环境变量为多用户配置不同的JDK(win)

    情景 同一服务器同时部署不同项目需要使用不同的JRE 环境 Windows Server 2008 需求 用户admin 需要使用jdk1.8 用户admin1 需要使用jdk1.7 解决 通过配置用 ...

  9. error: unpack failed: error Missing tree

    最近新建一个仓库,push时遇到如下问题,试了好多方法,最后在stackoverflow上找到解决办法了,可是在开始时就试过这方法,但不成.至于为嘛出现的这种错误,还是不明白原因. git.exe p ...

  10. C++11:实用特性

    今天逛cplusplus.com发现C++还真多了不少方便使用的特性,先了解些最常用的 初始化列表 vector<,,,}); vector<pair<int, int> &g ...