一、 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. Linux启动与关闭WIndows服务记录

    启动: mono-service -l:/var/run/Myservice-lock.pid MyService.exe (这个-l参数一定要加上) 控制服务: 暂停: kill -USR1 `ca ...

  2. 【Guava】PreConditions来校验参数

    前置条件:让方法调用的前置条件判断更简单. 在我们的日常开发中,经常要对入参进行一定的参数校验,比如是否为空,参数的取值范围是否符合要求等等.这种参数校验如果我们单独进行校验的话,代码的重复率比较高, ...

  3. Hibernate核心开发接口_SessionFactory详解

    SessionFactory: a)  用来产生和管理Session b)通常情况下每个应用只需要一个SessionFactory c)除非要访问多个数据库的情况 d) 关注两个方法即:  openS ...

  4. apktook 反编译错误

    Exception in thread "main" brut.androlib.err.UndefinedResObject: resource spec: 0x01010490 ...

  5. HUE配置文件hue.ini 的sqoop模块详解(图文详解)(分HA集群和非HA集群)

    不多说,直接上干货! 我的集群机器情况是 bigdatamaster(192.168.80.10).bigdataslave1(192.168.80.11)和bigdataslave2(192.168 ...

  6. DIY党的福利!鹅厂程序员教你200元以内制作专属分体键盘

    欢迎大家前往腾讯云+社区,获取更多腾讯海量技术实践干货哦~ 本文由VellHe发表于云+社区专栏 前言 作为一名程序员,键盘在手,天下我有啊,不整把高大上的键盘怎么提升B格.之前一直想买个机械键盘,听 ...

  7. 【转】WinForm窗体显示和窗体间传值

    以前对WinForm窗体显示和窗体间传值了解不是很清楚 最近做了一些WinForm项目,把用到的相关知识整理如下 A.WinForm中窗体显示 显示窗体可以有以下2种方法: Form.ShowDial ...

  8. D的小L

    D的小L 描述  一天TC的匡匡找ACM的小L玩三国杀,但是这会小L忙着哩,不想和匡匡玩但又怕匡匡生气,这时小L给匡匡出了个题目想难倒匡匡(小L很D吧),有一个数n(0<n<10),写出1 ...

  9. 通过开机广播(broadcast)通知应用

    1. 概念 开机的时候,系统会发送一则广播,所有有标记的应用(通过广播接收者)都会获取得到,然后可以通过广播接收者去处理一些事情,比如启动该应用,或者处理数据: 代码:https://github.c ...

  10. echart.js 参数解释

    Data参数 获取容器对象 var canvas = document.getElementById("myCanvas"); 渲染 var ctx = canvas.getCon ...