在大数组中查找
给一个按照升序排序的非负整数数组。这个数组很大以至于你只能通过固定的接口 ArrayReader.get(k) 来访问第k个数(或者C++里是ArrayReader->get(k)),并且你也没有办法得知这个数组有多大。
找到给出的整数target第一次出现的位置。你的算法需要在O(logk)的时间复杂度内完成,k为target第一次出现的位置的下标。
如果找不到target,返回-1。
class Solution{
public:
int searchBigSortedArray(ArrayReader* reader,int target){
int rangeTotal=1;
while(reader->get(rangeTotal-1)<target){
rangeTotal=rangeTotal*2;
}
int start=0,end=rangeTotal-1;
while(start+1<end){
int mid=start+(end-start)/2;
if(reader->get(mid)<target){
start=mid;
}
else{
end=mid;
}
}
if(reader->get(start)==target){
return start;
}
if(reader->get(end)==target){
return end;
}
return -1;
}
};
在排序数组中找最接近的K个数
给一个目标数 target, 一个非负整数 k, 一个按照升序排列的数组 A。在A中找与target最接近的k个整数。返回这k个数并按照与target的接近程度从小到大排序,如果接近程度相当,那么小的数排在前面。
class Solution {
public:
vector<int> kClosestNumbers(vector<int> &a, int target, int k) {
int left=findLowerClosest(a,target);
int right=left+1;
vector<int> result;
for(int i=0;i<k;i++){
if(isLeftClosest(a,target,left,right)){
result.push_back(a[left]);
left--;
}else{
result.push_back(a[right]);
right++;
}
}
return result;
}
bool isLeftClosest(vector<int>& a,int target,int left,int right){
if(left<0){
return false;
}
if(right>=a.size()){
return true;
}
return target-a[left]<=a[right]-target;
}
int findLowerClosest(vector<int>& a,int target){
int start=0,end=a.size()-1;
while(start+1<end){
int mid=start+(end-start)/2;
if(a[mid]<target){
start=mid;
}else{
end=mid;
}
}
//Lower|Upper 找分界线的最右面
if(a[end]<target){
return end;
}
if(a[start]<target){
return start;
}
/*
if(a[start]>=target){
return start;
}
if(a[end]>=target){
return end;
}
*/
return -1;
}
};
给 n 个整数的山脉数组,即先增后减的序列,找到山顶(最大值)。
class Solution {
public:
int mountainSequence(vector<int> &nums) {
if(nums.size()==0){
return -1;
}
int start=0,end=nums.size()-1;
while(start+1<end){
int mid=start+(end-start)/2;
if(nums[mid]>nums[mid+1]){
end=mid;
}else{
start=mid;
}
}
return max(nums[start],nums[end]);
}
};
寻找旋转排序数组中的最小值
假设一个按升序排好序的数组在其某一未知点发生了旋转(比如0 1 2 4 5 6 7 可能变成4 5 6 7 0 1 2)。你需要找到其中最小的元素。
class Solution {
public:
int findMin(vector<int> &nums) {
if(nums.size()==0){
return -1;
}
int start=0,end=nums.size()-1;
while(start+1<end){
int mid=start+(end-start)/2;
if(nums[mid]>nums[end]){
start=end;
}else{
end=mid;
}
}
return min(nums[start],nums[end]);
}
};
搜索旋转排序数组
给定一个有序数组,但是数组以某个元素作为支点进行了旋转(比如,0 1 2 4 5 6 7 可能成为4 5 6 7 0 1 2)。给定一个目标值target进行搜索,如果在数组中找到目标值返回数组中的索引位置,否则返回-1。你可以假设数组中不存在重复的元素。
class Solution {
public:
int search(vector<int> &a, int target) {
if(a.size()==0){
return -1;
}
if(a.size()==1){
return a[0] == target ? 0 : -1;
}
int result=-1;;
int start=0,end=a.size()-1;
while(start+1<end){
int mid=start+(end-start)/2;
if(a[mid]==target) return mid;
if(a[mid]>a[end]){
if(a[start]<=target&&target<=a[mid]){
end=mid;
}else{
start=mid;
}
}else{
if(a[mid]<=target&&target<=a[end]){
start=mid;
}else{
end=mid;
}
}
}
if(a[start]==target){
return start;
}
if(a[end]==target){
return end;
}
return -1;
}
};
寻找峰值
给定一个整数数组(size为n),其具有以下特点:
相邻位置的数字是不同的
A[0] < A[1] 并且 A[n - 2] > A[n - 1]
假定P是峰值的位置则满足A[P] > A[P-1]且A[P] > A[P+1],返回数组中任意一个峰值的位置。
class Solution {
public:
int findPeak(vector<int> &a) {
int start=0,end=a.size()-1;
while(start+1<end){
int mid=start+(end-start)/2;
if(a[mid]<a[mid-1]){
end=mid;
}else if(a[mid]<a[mid+1]){
start=mid;
}else{
return mid;
}
}
return a[start]<a[end]?end:start;
}
};
木材加工
有一些原木,现在想把这些木头切割成一些长度相同的小段木头,需要得到的小段的数目至少为 k。给定L和k,你需要计算能够得到的小段木头的最大长度。
class Solution {
public:
int woodCut(vector<int> &l, int k) {
if(l.size()==0){
return 0;
}
int maxLen=getMaxLen(l);
int start=1,end=maxLen;
if(end<1){
return 0;
}
while(start+1<end){
int mid=start+(end-start)/2;
if(isValidLen(mid,l,k)){
start=mid;
}else{
end=mid;
}
}
if(isValidLen(start,l,k)) return start;
if(isValidLen(end,l,k)) return end;
}
bool isValidLen(int target,vector<int>& l,int k){
int totalNum=0;
for(int len:l){
totalNum+=len/target;
}
return totalNum>=k;
}
int getMaxLen(vector<int>& l){
int maxLen=INT_MIN;
for(int len:l){
maxLen=max(maxLen,len);
}
return maxLen;
}
};