LintCode天梯(USGiants)-Binary Search
来源:互联网 发布:淘宝1.74非球面镜片 编辑:程序博客网 时间:2024/05/28 04:53
喵,小喵爬天梯系列~美国大公司。
第三梯:二分查找
首先给出一个二分框架:
low,highwhile(low <= high){ x = (low + high) / 2; if(judge(a[x])){ low = x+1; } else{ high = x-1; }}judge(x):是一个判断的条件。
1、Sqrt(x)
题意:
实现 int sqrt(int x) 函数,计算并返回 x 的平方根。
分析:
sqrt(x)大家影帝啊日常使用这个函数,现在我们怎么搞出来这个算法呢?稍微用一些数学公式即可,什么二分、牛顿等。给出x求出一个a。
使得x = a^2。变形得到x - a^2 = 0;现在给出x,便利a即可,范围是[0,a],这样的话,小喵就很惊喜,排序数组已经出来,现在就是二分,二分就来了,剩下的就是我们最熟悉的二分框架了。
Code:
class Solution {public: /** * @param x: An integer * @return: The sqrt of x */ int sqrt(int x) {//äşŒĺˆ† // write your code here long long a=0,b=x; while(a < b){ long long m = (a+b)/2; if(m*m == x) break; else if(m*m > x) b = m-1; //第一个judge(x) else a = m+1; } if(b*b > x) b-=1; return b; }};
小喵总结:看到有序的时候,能否想到二分;当无序的时候,能否通过排序的情况下,二分降低时间复杂度。
2、Search Insert Position
题意:
给定一个排序数组和一个目标值,如果在数组中找到目标值则返回索引。如果没有,返回到它将会被按顺序插入的位置。
你可以假设在数组中无重复元素。
分析:
这就是二分的框架,没有任何转化。题目给定数组中无重复元素,如果有重复元素,让你找到最前和最后的位置,你只需要在返回的位置上,前后试探一下即可。
Code:
class Solution { /** * param A : an integer sorted array * param target : an integer to be inserted * return : an integer */public: int searchInsert(vector<int> &A, int target) { // write your code here if(A.size() == 0) return 0; int low = 0,high = A.size(); while(low < high){ int mid = (low + high) / 2; if(A[mid] == target) return mid; else if(A[mid] < target) low = mid + 1; else high = mid ; } return high; }};
小喵总结:号称能写对二分算法的程序员不到一半。其实我们我们确实很容易忘掉这个边界问题。
3、Search a 2D Matrix
题意:
写出一个高效的算法来搜索 m × n矩阵中的值。
这个矩阵具有以下特性:
每行中的整数从左到右是排序的。
每行的第一个数大于上一行的最后一个整数。
分析:
这就是一个排序的数组,强行分成一个二维的矩阵,很明显遍历一遍,得到结果。O(mn)。既然整体有序,我们可以对[1-mn]进行二分,时间O(log(mn)) = O(log(m)+log(n))。我们唯一需要做的就是mid = (low+high)/2,将mid转化到二维数组的位置,(这是你是不是想起大学学的数据结构是,多维数组的转化还是有一定用处的,)m x n。
row = mid / m; column = mid % n。搞定,下面就是写出一个正确的二分算法就好了。
Code:
class Solution {public: /** * @param matrix, a list of lists of integers * @param target, an integer * @return a boolean, indicate whether matrix contains target */ /** 此处是直接遍历的代码 bool searchMatrix(vector<vector<int> > &matrix, int target) { // write your code here if(matrix.size() == 0 ) return false; int c = matrix.size(); //čĄŒ int r = matrix[0].size(); //ĺˆ— int k; for(k = 0;k < c && target > matrix[k][r - 1];k ++); if(k == c) return false; for(int i = 0; i < r; i ++){ if(matrix[k][i] == target) return true; } return false; } **/ bool searchMatrix(vector<vector<int> > &matrix, int target){ if(matrix.size() == 0) return false; int m = matrix.size(), n= matrix[0].size(); int mid,low = 0, high = m*n-1; while(low <= high){//二分这个思想,可以很简单,但是边界一定要注意 mid = low + (high - low)/2; if(target == matrix[mid/n][mid%n]){ return true; } else if(target < matrix[mid/n][mid%n]){ high = mid - 1; } else low = mid + 1; } return false; }};
4、First Position of Target
题意:
给定一个排序的整数数组(升序)和一个要查找的整数target,用O(logn)的时间查找到target第一次出现的下标(从0开始),如果target不存在于数组中,返回-1。
分析:
这题就是我上面提到的,如果要求返回的是第一个和最后一个这个值的下标呢?此时就用到了我说的前后试探法。最坏情况下O(n/2)。
Code:
class Solution {public: /** * @param nums: The integer array. * @param target: Target number to find. * @return: The first position of target. Position starts from 0. */ int binarySearch(vector<int> &A, int target) { // write your code here if(A.size() == 0) return -1; int mid, low = 0,high = A.size() - 1; while(low <= high){ mid = (low + high) / 2; if(A[mid] == target) break; else if(A[mid] < target) low = mid + 1; else high = mid-1 ; } if(low > high) return -1; while(mid > 0 && A[mid - 1] == target){ mid --; } return mid; }};
5、Find Minimum in Rotated Sorted Array
题意:
假设一个旋转排序的数组其起始位置是未知的(比如0 1 2 4 5 6 7 可能变成是4 5 6 7 0 1 2)。
你需要找到其中最小的元素。
分析:
这里我推荐先看代码,再看解释,既然是二分的章节,那么问题是怎么二分呢?首先我们要知道旋转后的数组的性质,旋转之后,我们得到两个连续的有序数组,假设原数组A,旋转之后得到两个有序数组ab,mid = (low+high)/2;每一次判断A[mid] > A[high] 最小值一定在右边部分, 我们可以看到high位置一定是b部分的最大值,mid位置可能是a部分的任意值或者是b部分的值,连续这个性质,我们可以得到这个结果。(我知道我没有说清楚,各位别打我)。反之,最小值在左边。
Code:
class Solution {public: /** * @param num: a rotated sorted array * @return: the minimum number in the array */ int findMin(vector<int> &num) { // write your code here int high=num.size()-1; int low=0,mid; while(low<high){ mid=(low+high)/2; if(num[mid]>num[high]) low=mid+1; else high=mid; } return num[low]; }};
6、Find Peak Element
题意:
你给出一个整数数组(size为n),其具有以下特点:
相邻位置的数字是不同的A[0] < A[1] 并且 A[n - 2] > A[n - 1]
假定P是峰值的位置则满足A[P] > A[P-1]且A[P] > A[P+1],返回数组中任意一个峰值的位置。
分析:
我们可以直接套用二分的框架,只是在判断是时候,比较的a[mid]和a[mid-1]或者a[mid]和a[mid+1]。对于这用一条语句的判断,我们一般不写成一个judge(x)的函数,但是这个函数的思想是必要的,因为这是二分搜索时,最需要关注的地方,之后才是二分的边界问题。
Code:
class Solution {public: /** * @param A: An integers array. * @return: return any of peek positions. */ int findPeak(vector<int> A) { // write your code here int start, end, mid; start = 1; end = A.size() - 2; while(start + 1 < end){ mid = (start + end) / 2; if(A[mid] < A[mid - 1]){ end = mid; } else{ start = mid; } } if(A[start] < A[end]) return end; else return start; }};
7、First Bad Version
题意:
代码库的版本号是从 1 到 n 的整数。某一天,有人提交了错误版本的代码,因此造成自身及之后版本的代码在单元测试中均出错。请找出第一个错误的版本号。
你可以通过 isBadVersion 的接口来判断版本号 version 是否在单元测试中出错,具体接口详情和调用方法请见代码的注释部分。
分析:
isBadVersion就是我们框架中的judge函数,只需要替换一下就可以了。
Code:
/** * class SVNRepo { * public: * static bool isBadVersion(int k); * } * you can use SVNRepo::isBadVersion(k) to judge whether * the kth code version is bad or not.*/class Solution {public: /** * @param n: An integers. * @return: An integer which is the first bad version. */ int findFirstBadVersion(int n) { // write your code here int low=1,high=n,mid; while(low<=high){ mid = (low+high)/2; if(SVNRepo::isBadVersion(mid)) high = mid-1; else low = mid+1; } return low; }};
8、Search in Rotated Sorted Array
题意:
假设有一个排序的按未知的旋转轴旋转的数组(比如,0 1 2 4 5 6 7 可能成为4 5 6 7 0 1 2)。给定一个目标值进行搜索,如果在数组中找到目标值返回数组中的索引位置,否则返回-1。
分析:
这次可以第五题的框架,只是在条件的内部,需要再加上一个判断,确定这个target是否在当前的部分之中。
Code:
class Solution { /** * param A : an integer ratated sorted array * param target : an integer to be searched * return : an integer */public: int search(vector<int> &A, int target) { // write your code here if(A.size() == 0) return -1; int f=0,e=A.size()-1,m; while(f<=e){ m = (f + e) / 2; if(A[m] == target) return m; if(A[f] <= A[m]){ if(target >= A[f] && target <= A[m]) e = m - 1; else f = m + 1; } else{ if(target <= A[e] && A[m] <= target) f = m + 1; else e = m - 1; } } return -1; }};
9、Search for a Range
题意:
给定一个包含 n 个整数的排序数组,找出给定目标值 target 的起始和结束位置。
如果目标值不在数组中,则返回[-1, -1]
分析:
二分框架+左右试探。还可以使用C++中的库函数。
Code:
class Solution { /** *@param A : an integer sorted array *@param target : an integer to be inserted *return : a list of length 2, [index1, index2] */public: /** //使用C++库函数 vector<int> searchRange(vector<int> &A, int target) { // write your code here vector<int> res; vector<int>::iterator f,e; f = lower_bound(A.begin(),A.end(),target); e = upper_bound(A.begin(),A.end(),target); if(f==A.end()||*f!=target){ res.push_back(-1); res.push_back(-1); } else{ res.push_back(f-A.begin()); res.push_back(e-A.begin()-1); } return res; } **/ //二分+左右试探,注意边界 vector<int> searchRange(vector<int> &A, int target){ int mid, low = 0,high = A.size() - 1; vector<int> res(2,-1); if(high == -1) return res; while(low <= high){ mid = (low + high) / 2; if(A[mid] == target) break; else if(A[mid] < target) low = mid + 1; else high = mid-1 ; } if(A[mid] != target) return res; low = high = mid; while(low > 0 && A[low - 1] == target){ low --; } while(high < A.size() - 1 && A[high + 1] == target){ high ++; } res[0] = low; res[1] = high; return res; } };
10、Wood Cut
题意:
有一些原木,现在想把这些木头切割成一些长度相同的小段木头,需要得到的小段的数目至少为 k。当然,我们希望得到的小段越长越好,你需要计算能够得到的小段木头的最大长度。
分析:
我们需要的最大长度L,最大长度L是多少?肯定在[0,maxlength]之间的一个数。此时我们注意到了一个排序的数组,能否二分?judge(x)怎么计算?注意到题目要求至少是k个小段,judge(x)只需要能否满足k个即可,如果得到的小木块大于k,可以得到mid = low + 1;否则high = mid - 1。
Code:
class Solution {public: /** *@param L: Given n pieces of wood with length L[i] *@param k: An integer *return: The maximum length of the small pieces. */ int judgeLength(vector<int> L, int k, int length){ if(length == 0) return -1; int cnt = 0; for(int i = 0; i < L.size(); i ++){ cnt += L[i] / length; } if(cnt < k) return 0; if(cnt >= k) return 1; //长度短 } int woodCut(vector<int> L, int k) { // write your code here long long maxlen = 0, minlen = 0, midlen = 0; for(int i = 0; i < L.size(); i ++){ if(maxlen < L[i]) maxlen = L[i]; } while(minlen <= maxlen){ midlen = (maxlen + minlen) / 2; if(judgeLength(L, k, midlen) == 1){ minlen = midlen + 1; } else if(judgeLength(L, k, midlen) == 0){ maxlen = midlen - 1; } else{ break; } } return maxlen; }};
- LintCode天梯(USGiants)-Binary Search
- LintCode天梯(USGiants)-String
- LintCode天梯(USGiants)-Integer Array
- #LintCode# Binary Search
- lintcode Binary Search
- LintCode Binary Search 二分查找
- lintcode:Validate Binary Search Tree
- lintcode: Unique Binary Search Trees
- [Lintcode]Binary Search Tree Iterator
- Unique Binary Search Trees--lintcode
- lintcode:Search Range in Binary Search Tree
- lintcode: Search Range in Binary Search Tree
- Lintcode - Remove Node in Binary Search Tree
- 20150624 lintcode 总结 Validate Binary Search Tree
- 20150708 lintcode 总结 Binary Search Tree Iterator
- LintCode | Easy | 二分查找 | Binary Search
- lintcode:Remove Node in Binary Search Tree
- lintcode:Unique Binary Search Trees II
- 关于Java SE、Java EE、Java ME三者的基本看法和理解.
- 二维数组的创建
- .NET之读写文件的方法
- android
- 蒲慕明教授写给他实验室工作人员和学生的信
- LintCode天梯(USGiants)-Binary Search
- JSP获取绝对路径(java代码)
- mfc 不支持尝试执行的操作 错误
- tableView的每个section 的headerView或者footerView随tableView一起滚动
- 公司内部wiki,你建立了么?
- jquery对象怎么转换为html对象(也就是js的dom对象)
- 在windows上 部署 Redis cluster模式的集群服务
- ASP.NET页面传值汇总 (Session / Server.Transfer / Query String / Cookie / Application )
- 2017.06.01回顾