1、一个各不相同元素的数组,求它的一个局部最小值。
局部极小值的定义为:一个值比左右相邻的值都小。
算法:如果o(n)遍历的话很容易求得一个全局最小值。当然是局部最小值。
也可以用二分查找算法,局部最小值一定在两个波峰之间。规定数组两端都是正无穷,那么局部最小值一定在两个波峰之间。可以比较mid与mid+1,如果小于mid+1那么mid+1就是一个波峰,局部最小值在mid前半部分;如果大于mid+1,那么mid就是一个波峰,局部最小值在mid后半部分
同理可以求得局部最大值。
class Solution {
public:
int halfPeak(vector<int>nums,int start,int end){
int mid = (start + end ) /2 ;
//如果mid是首元素,那么大于后一个值就是局部最大值
if(mid == 0 && nums[mid]>nums[mid+1])
return mid;
//如果mid不是首元素,那么大于两边就是局部最大值
if(mid!=0 && nums[mid]>nums[mid+1] && nums[mid] >nums[mid-1])
return mid;
//如果不满足条件,则判断后继续寻找。局部最大肯定在两个波谷之间
if(nums[mid] <nums[mid+1])
return halfPeak(nums,mid+1,end);
else
return halfPeak(nums,start,mid);
}
int findPeakElement(vector<int>& nums) {
if(nums.size() <2)
return 0;
nums.push_back(INT_MIN);
return halfPeak(nums,0,nums.size()-1);
}
};
2、找到数组第一个缺失的正整数。【1,3】缺失的是2.【4,5】缺失的是1.数组里应该是【1,2】
算法:构造一个等长度的数组,存放类似哈希表的数出现值
class Solution {
public:
int firstMissingPositive(vector<int>& nums) {
if(nums.size()==0)
return 1;
vector<int>save;
save.resize(nums.size());
//构造辅助数组,出现的数字是1,没出现的是0
for (int i = 0; i < nums.size(); i++)
{
if(nums[i]>0 && nums[i] <=nums.size())
save[nums[i]-1] = 1;
}
//在辅助数组里找空缺的数字
for (int i = 0; i < save.size(); i++)
{
if(save[i] == 0)
return i+1;
}
//如果数组里的数字是全的,那么缺失的是更大的数字
return nums.size()+1;
}
};
3、前缀和、前缀积的应用
前缀积的应用可以参考b[i]=a[0]a[1]…a[i-1]a[i+1]…的例题,使用先求出后缀积,再对应的乘上前缀积得出跳过a[i]的答案。
前缀和可以参考例题:把一个数组从中间任意位置P分开,使得前一半和与后一半和差值最小
算法:第一次遍历,得出前缀和
第二次对前缀和数组进行遍历,比较前一部分和总值减去前部分的差值进行差值比较。
class Solution {
public:
int maxFrontSum(vector<int>& nums) {
if(nums.size()<2)
return 0;
int tmp = 0;
for (int i = 0; i < nums.size(); i++)
{
tmp += nums[i];
nums[i] = tmp;
}
int sum = tmp;
int maxvalue = -1;
//记录分割点
int res = -1;
for (int i = 0; i < nums.size()-1; i++)
{
//当前前缀和
int pre = nums[i];
//其余后部分的和
int behind = sum - pre;
//差值
int gap = abs(behind - pre );
maxvalue = max(maxvalue,gap);
//如果最大差值改变了,说明当前分割点可能是最大差值分割点
if(maxvalue == gap)
res = i;
}
//返回的数字是分割的前部分
return res;
}
};
通过前缀和的应用可以在O(N)的时间内找到分割点,所以对于涉及到和或者差的问题,想到前缀和与前缀差等概念。