寻找峰值
首先,确定峰值存在–数组边界都为负无穷,而数组元素为整数,所以肯定存在一个峰值。
如果我们将每个元素都看成一个点,这个点可能处于山顶(就是我们想要的情况),也可能处于山底(不是我们要的),也可能正在爬坡或下坡,对于这两种情况,我们怎么确定峰值在哪里?如果我们让这个点一直下坡,我们可能会越过谷底到达山顶,也可能一直到边界-谷底,但我们要让他一直上坡的话,就一定能找到峰值。
再说下时间复杂度:
总共有n个元素,每次查找的区间大小就是n,n/2,n/4,…,n/2^k(接下来操作元素的剩余个数),其中k就是循环的次数。
由于n/2k取整后>=1,即令n/2k=1,
可得k=log2n,(是以2为底,n的对数),所以时间复杂度可以表示O()=O(logn)。
例题:链接: link
假设数组长度为 n,注意到数组arr 已经按照升序排序,我们可以将数组 分成两部分,前一部分所有元素 [0,left]都小于 x,后一部分所有元素[right,n−1] 都大于等于 x,left 与 right 都可以通过二分查找获得。
left 和 right指向的元素都是各自部分最接近 x 的元素,因此我们可以通过比较 left和 right指向的元素获取整体最接近 x 的元素。如果 x−arr[left]≤arr[right]−x,那么将 left 减一,否则将 right 加一。相应地,如果 left或 right已经越界,那么不考虑对应部分的元素。
最后,区间 [left+1,right−1]的元素就是我们所要获得的结果,返回答案既可。
int binarySearch(const int* arr, int arrSize, int x) {
int low = 0, high = arrSize - 1;
while (low < high) {
int mid = low + (high - low) / 2;
if (arr[mid] >= x) {
high = mid;
} else {
low = mid + 1;
}
}
return low;
}
int* findClosestElements(int* arr, int arrSize, int k, int x, int* returnSize) {
int right = binarySearch(arr, arrSize, x);
int left = right - 1;
while (k--) {
if (left < 0) {
right++;
} else if (right >= arrSize) {
left--;
} else if (x - arr[left] <= arr[right] - x) {
left--;
} else {
right++;
}
}
int *res = (int *)malloc(sizeof(int) * (right - left - 1));
memcpy(res, arr + left + 1, sizeof(int) * (right - left - 1));
*returnSize = right - left - 1;
return res;
}
头文件#include<string.h>
三分法
二分是把区间分为长度相等的两段,三分则是把区间分为长度相等的三段,进行查找,二分算法的要求是搜索的序列是单调序列,而三分法所面向的搜索序列的要求是:序列为一个凸性函数。如图所示,已知函数f(x)在点left和点right中间存在一个极值点,现在我们的任务就是找到这个极值点或者计算函数在这个区间上的极值。在这里,与二分法图片不同的是,mid点有左右两个(都是三等分点)
mid1=left+(right-left)/3;
mid2=right-(right-left)/3;
在进行迭代的时候,计算f(midl)和f(midr)并比较大小,发现有f(midl)>f(midr),说明midr距离极值点更近,因此应该将left点进行更新,如下图所示。
在经过若干次迭代之后,right-left会越来越小,并小于一个值eps,此时结束迭代。我们可以通过调整eps的大小控制极值点求解的精度。
值得注意的是,我们应根据所求极值点(极大值|极小值)对判断条件应做出相应调整,即求极大值时,当f(midl) > f(midr),说明左端点距离极大值点更近,因此应该更新right。
double th_division(double left, double right, double eps)
{ //求解极小值点
double midl, midr;
while (right - left > eps)
{
midl = (2 * left + right) / 3;
midr = (left + 2 * right) / 3;
if (f(midl) > f(midr)) // f是需要求的函数
left = midl;
else
right = midr;
}
return midl; //返回近似极值点
}
将数字拆成3的幂
方法一:进制的转化
我们可以将 n转换成 3进制。如果 n的 3进制表示中每一位均不为 2,那么答案为 True,否则为 False。
例如当 n=12 时,12=(110)3 ,满足要求;当 n=21 时,21=(210)3 ,不满足要求。
bool checkPowersOfThree(int n) {
while (n) {
if (n % 3 == 2) {
return false;
}
n /= 3;
}
return true;
}
方法二:出队列入队列