Day6 2020.07.22&&2020.07.23
1.search-for-a-range
给出一个有序数组,请在数组中找出目标值的起始位置和结束位置,你的算法的时间复杂度应该在O(log n)之内,如果数组中不存在目标,返回[-1, -1].
例如:给出的数组是[5, 7, 7, 8, 8, 10],目标值是8,返回[3, 4].
解题思路:题目要求 O(log n),找到目标值然后前后扫描,当遇到全部一样的数字不符合时间复杂度要求了。可以进行两次二分查找,查找的过程中每一次找到一个边界。
class Solution {
public:
vector<int> searchRange(int* A, int n, int target) {
vector<int> result={-1,-1};
int low1=0,high1=n-1;
//查找右边界
while(low1<=high1){
int mid1=(high1+low1)/2;
if(A[mid1]<=target)
low1=mid1+1;
else
high1=mid1-1;
}
int low2=0,high2=n-1;
while(low2<=high2){
int mid2=(low2+high2)/2;
if(A[mid2]>=target)
high2=mid2-1;
else
low2=mid2+1;
}
if(low2<=high1){
result[0]=low2;
result[1]=high1;
}
return result;
}
};
2.search-insert-position
给出一个有序的数组和一个目标值,如果数组中存在该目标值,则返回该目标值的下标。如果数组中不存在该目标值,则返回如果将该目标值插入这个数组应该插入的位置的下标,假设数组中没有重复项。
下面给出几个样例:
[1,3,5,6], 5 → 2
[1,3,5,6], 2 → 1
[1,3,5,6], 7 → 4
[1,3,5,6], 0 → 0
class Solution {
public:
int searchInsert(int* A, int n, int target) {
if(n==0) return 0;
for(int i=0;i<n;i++){
if(A[i]>=target)
return i;
}
}
};
3.search-a-2d-matrix
请写出一个高效的在m*n矩阵中判断目标值是否存在的算法,矩阵具有如下特征:
每一行的数字都从左到右排序
每一行的第一个数字都比上一行最后一个数字大
例如对于下面的矩阵:
[↵ [1, 3, 5, 7],↵ [10, 11, 16, 20],↵ [23, 30, 34, 50]↵]
要搜索的目标值为3,返回true;
解题思路:两次折半查找,第一次是在最后列中查找,第二次是在第一次查找到的列数对应的行中查找。
class Solution {
public:
bool searchMatrix(vector<vector<int> >& matrix, int target) {
if(matrix.empty()) return false;
int size_row=matrix.size();
int size_col=matrix[0].size();
//折半查找
int low=0,high=size_row-1,mid;
while(low<=high){
mid=(low+high)/2;
if(matrix[mid][size_col-1]==target) return true;
else if(matrix[mid][size_col-1]<target) low=mid+1;
else high=mid-1;
}
//再在matrix[mid][]这一行中查找
int tag;
if(mid>=0&&mid<size_row) tag=mid;
else return false;
low=0; high=size_col-1;
while(low<=high){
mid=(low+high)/2;
if(matrix[tag][mid]==target) return true;
else if(matrix[tag][mid]<target) low=mid+1;
else high=mid-1;
}
return false;
}
};
4.first-bad-version
你是产品经理,目前正在带领一个团队开发新的产品。不幸的是,你的产品的最新版本没有通过质量检测。由于每个版本都是基于之前的版本开发的,所以错误的版本之后的所有版本都是错的。假设你有 n 个版本 [1, 2, …, n],你想找出导致之后所有版本出错的第一个错误的版本。你可以通过调用 bool isBadVersion(version) 接口来判断版本号 version 是否在单元测试中出错。实现一个函数来查找第一个错误的版本。你应该尽量减少对调用 API 的次数。
示例:
给定 n = 5,并且 version = 4 是第一个错误的版本。
调用 isBadVersion(3) -> false
调用 isBadVersion(5) -> true
调用 isBadVersion(4) -> true
所以,4 是第一个错误的版本。
解题思路:因为这题中的二分查找是找到边界,所以循环跳出的条件是low==high,并且在查找过程中mid=low+(high-low)/2,high=mid。
class Solution {
public:
int firstBadVersion(int n) {
int low=1,high=n;
//不能写 int mid = (lo + hi) / 2; 要写 int mid = lo + (hi - lo) / 2;
while(low<high){
int mid=low+(high-low)/2;
if(isBadVersion(mid)==false) low=mid+1;
else high=mid; //且此处是high=mid,因为此时的版本可能是第一个错误版本
}
//循环结束的条件是low==high
return low;
}
};
5.find-minimum-in-rotated-sorted-array
假设按照升序排序的数组在预先未知的某个点上进行了旋转。( 例如,数组 [0,1,2,4,5,6,7] 可能变为 [4,5,6,7,0,1,2] )。请找出其中最小的元素。你可以假设数组中不存在重复元素。
示例 1:输入: [3,4,5,1,2] 输出: 1
示例 2:输入: [4,5,6,7,0,1,2]输出: 0
//时间复杂度为O(n)
class Solution {
public:
int findMin(vector<int>& nums) {
if(nums.empty()) return -1;
for(int i=0;i<nums.size()-1;i++){
if(nums[i]>nums[i+1]) return nums[i+1];
}
return nums[0];
}
};
解题思路:leetcode上的,和first-bad-version一样,寻找边界问题。
class Solution {
public:
int findMin(vector<int>& nums) {
int low=0,high=nums.size()-1;
while(low<high){
int mid=low+(high-low)/2;
if(nums[mid]<nums[high]){
high=mid;
}else{
low=mid+1;
}
}
return nums[low];
}
};
6.find-minimum-in-rotated-sorted-array-ii
注意数组中可能存在重复的元素。
同find-minimum-in-sorted-array第一种解法一样,复杂度还是O(n)。
第二种解法:
class Solution {
public:
int findMin(vector<int>& nums) {
int low=0,high=nums.size()-1;
while(low<high){
int mid=low+(high-low)/2;
if(nums[mid]>nums[high]){
low=mid+1;
}else if(nums[mid]<nums[high]){
high=mid;
}else high--;//要考虑重复数字即mid元素等于high元素的情况
}
return nums[low];
}
};
7.search-in-rotated-sorted-array
给出一个转动过的有序数组,你事先不知道该数组转动了多少
(例如,0 1 2 4 5 6 7可能变为4 5 6 7 0 1 2).在数组中搜索给出的目标值,如果能在数组中找到,返回它的索引,否则返回-1。
假设数组中不存在重复项。
== 解题思路:还是用二分法,但是移动的时候在判定语句中加上条件,判断目标值所在的区间。==
class Solution {
public:
int search(int* A, int n, int target) {
if(n==0) return -1;
int low=0,high=n-1;
while(low<=high){
int mid=low+(high-low)/2;
if(target==A[mid]) return mid;
//前半部分是从小到大 target在前半部分
if(A[low]<=A[mid]&&(A[low]<=target&&target<A[mid])){
high=mid-1;
}else if(A[mid]<=A[high]&&!(A[mid]<target&&target<=A[high])){
high=mid-1;
}else
low=mid+1;
}
return -1;
}
};
8.search-in-rotated-sorted-array-ii
继续思考题目 “Search in Rotated Sorted Array”:
如果数组种允许有重复元素怎么办?
会影响时间复杂度吗?是怎样影响时间复杂度的,为什么?
编写一个函数判断给定目标值是否在数组中。
class Solution {
public:
bool search(int* A, int n, int target) {
if(n==0) return false;
int low=0,high=n-1;
while(low<=high){
int mid=(low+high)/2;
if(target==A[mid]) return true;
else if(A[mid]>A[low]){
if(A[low<=target]&&target<=A[mid]) high=mid-1;
else low=mid+1;
}else if(A[low]==A[mid]){
low++;
}else{
if(A[mid]<=target&&target<=A[high]) low=mid+1;
else high=mid-1;
}
}
return false;
}
};