一、 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开发中的BaseAdapter之理解(引用自网络,总结的很好,谢谢)

    android中的适配器(Adapter)是数据与视图(View)之间的桥梁,用于对要显示的数据进行处理,并通过绑定到组件进行数据的显示. BaseAdapter是Android应用程序中经常用到的基 ...

  2. C#中的委托 Delegate(委托 也叫代表,代表一类方法)

    1. 委托类似与 C或C++中的函数指针,但委托是 面向对象的,并且是类型安全的 详情可查看官方文档:https://msdn.microsoft.com/en-us/library/ms173172 ...

  3. 快捷键 -- windows

    win+数字 :   打开任务栏第n个图标 Win+D :快速显示桌面 Win+R :快速运行打开软件 例如 cmd services,msc Win+E:打开资源管理器 Win+L:快速锁定计算机 ...

  4. ZOJ 2971 Give Me the Number

    Give Me the Number Numbers in English are written down in the following way (only numbers less than  ...

  5. 关于css浮动框是否脱离文档流的分析

    在了解浮动属性之前,首先我们先了解一下html中关于display属性的相关知识. display属性常用的有inline, block, inline-block. inline也就是内联的意思. ...

  6. Java SPI

    一.什么是Java SPI? SPI的全名为Service Provider Interface.大多数开发人员可能不熟悉,因为这个是针对厂商或者插件的.在java.util.ServiceLoade ...

  7. [转]C#中Timer使用及解决重入问题

    本文转自:http://www.cnblogs.com/hdkn235/archive/2014/12/27/4187925.html ★前言 打开久违的Live Writer,又已经好久没写博客了, ...

  8. amazeui笔记-web组件

    Json.parse()

  9. 如鹏网学习笔记(五)MySql基础

    MySQL基础 一.数据库概念 1,网友装备信息.论坛帖子信息.QQ好友关系信息.学籍管理系统中的学生信息等都要“持久化”的保存到一个地方, 如果通过IO写到文件中,那么会非常麻烦,而且不利于多人共享 ...

  10. ASP.NET 解决在点击Button执行服务器事件之前验证用户输入并阻塞

    在网站项目开发时,为了减少用户的错误性的操作,很多时候我们都需要做一些必要的JS验证来提醒用户,比如:“输入的值不符合规则,请重新输入”.“提交后无法修改,您确定要继续吗?”友好性的提示. 这时候我们 ...