一、 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. clipse validation 优化设置

  2. java中的this和super(构造函数)

    1.this:表示当前对象 常用的代码: public class A{ private String name; public void setName(String name){ this.nam ...

  3. finally是否始终执行

    The only times finally won't be called are: If you call System.exit() If the JVM crashes first If th ...

  4. 我与ARM的那些事儿1初识ARM

    最近一直在研究ARM,说到ARM,我们首先想到了是三星.高通等公司,这些公司都制造CPU的,其实ARM也是一家公司,只不过它是提供最核心的逻辑电路,而且它的赚钱方式是与其他公司进行双赢的!你卖出多少芯 ...

  5. 每天一道leetcode203-移除链表的元素

    考试结束,班级平均分只拿到了年级第二,班主任于是问道:大家都知道世界第一高峰珠穆朗玛峰,有人知道世界第二高峰是什么吗?正当班主任要继续发话,只听到角落默默想起来一个声音:”乔戈里峰” 前言 2018. ...

  6. 9.Symbol

    Symbol Symbol 概述 ES5 的对象属性名都是字符串,这容易造成属性名的冲突.比如,你使用了一个他人提供的对象,但又想为这个对象添加新的方法(mixin 模式),新方法的名字就有可能与现有 ...

  7. WCF-netTcpBinding端口共享

    在同一台机器上一个端口在某时刻只能被一个应用程序占用.对于WCF服务来说,如果服务器上有多个服务并且这些服务寄宿在不同的应用程序中,我们需要某种途径来共享它们的端口.下面是一个示例来演示使用TcpBi ...

  8. jquery实现的让图片在网页的可视区域里四处漂浮的效果

    本文分享给大家一个用jquery开发的图片漂浮效果. jquery图片漂浮效果,常见的就是网页里四处漂来漂去的广告了,漂到边缘时还会反弹和拐弯. 下面来看具体的代码,先看要实现漂亮效果的这个jquer ...

  9. JS实现最小生成树之克鲁斯卡尔(Kruskal)算法

    克鲁斯卡尔算法打印最小生成树: 构造出所有边的集合 edges,从小到大,依次选出筛选边打印,遇到闭环(形成回路)时跳过. JS代码: //定义邻接矩阵 let Arr2 = [ [0, 10, 65 ...

  10. IDEA使用maven建web项目示例

    运行环境:OSX-10.13.3. IDEA-2017.3.3. maven-3.5.2 步骤1:选择maven-webapp模板新建web项目 步骤2:设置项目GroupId等 需从网上下载相关构件 ...