一、 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. 在Android中调用KSOAP2库访问webservice服务出现的服务端传入参数为null的问题解决

    ksoap2-android-3.0.0-jar 第三方库来调用.net 写的Web Service 如果没有参数,那么调用一切顺利,但是如果服务是带参数的,那么服务端接收的参数都是nul.      ...

  2. Idea与Eclipse操作代码的快捷方式

    1.Idea格式化代码的快捷键:ctrl+alt+L 2.在IDEA中创建了properties文件,发现默认中文不会自动进行unicode转码.如下 在project settings - File ...

  3. Linux 命令学习之cd

    功能说明: cd 命令是 linux 最基本的命令语句,其他的命令都会依赖与 cd 命令.因此学好 cd 命令是必须的. 语 法:cd [目的目录] 补充说明:cd指令可让用户在不同的目录间切换,需要 ...

  4. MapReduce原理——分而治之

    一.MapReduce简介 二.MapReduce并行处理的基本过程 三.MapReduce实际处理流程 四.一个job的运行流程 一.MapReduce简介 MapReduce是一种并行可扩展计算模 ...

  5. js empty() vs remove()

    转自:jQuery empty() vs remove() empty() will remove all the contents of the selection. remove() will r ...

  6. java1.8中ConcurrentHashMap

    java1.8中的ConcurrentHashMap做了非常大的改动,整个数据结构都发生了变化,已经不存在segment了.所以要好好重新查看下源码.这篇博客是逐步更行的,看一点写一点. 首先看一个很 ...

  7. minStack实现

    设计包含 min 函数的栈(栈)定义栈的数据结构,要求添加一个 min 函数,能够得到栈的最小元素.要求函数 min.push 以及 pop 的时间复杂度都是 O(1). #include <a ...

  8. vlog常用参数解析

    1. -f <filelist> : compile all files in filelist --------------------------------------------- ...

  9. 【转】检测到在集成的托管管道模式下不适用的ASP.NET设置的解决方法(非简单设置为【经典】模式)。

    检测到在集成的托管管道模式下不适用的ASP.NET设置的解决方法(非简单设置为[经典]模式). 我们将ASP.NET程序从IIS6移植到IIS7,可能运行提示以下错误: HTTP 错误 500.23 ...

  10. Java泛型的协变

    在上篇<Java泛型的基本使用>这篇文章中遗留以下问题,即将子类型也能添加到父类型的泛型中,要实现这种功能必须借助于协变. 实验准备 现在在上篇文章展示的Decorator类型的基础上,增 ...