852. 山脉数组的峰顶索引
思路:一开始理解错误了…仔细看了下题目发现很简单嘛。可以直接扫描,也可以用效率更高的二分查找.
扫描:
class Solution {
public:
int peakIndexInMountainArray(vector<int>& A) {
int res = 1;
while (A[res - 1] < A[res]) ++res;
; //NULL
return res - 1;
}
};
时间复杂度:O(n)
二分查找:
class Solution {
public:
int peakIndexInMountainArray(vector<int>& A) {
int left = 0, right = A.size() - 1;
int mid = 0;
while (left < right)
{
mid = (left + right) >> 1;
if (A[mid - 1] < A[mid] && A[mid] > A[mid + 1])
return mid;
if (A[mid - 1] < A[mid])
left = mid;
else
right = mid;
}
return right;
}
};
时间复杂度:O(mlogN)
1351. 统计有序矩阵中的负数
思路:矩阵中没列都是一个有序的序列,因此可以考虑用二分查找,后缀倒序遍历,但从算法总体效率以及稳定性而言二分查找显然更胜一筹。
class Solution {
public:
int countNegatives(vector<vector<int>>& grid) {
int total = 0;
size_t hi = 0;
size_t lo = 0;
for (auto subGrid : grid)
{
hi = subGrid.size();
int res = binSearch(subGrid, -1, lo, hi); //注意,这里必须要为-1不能是0.
total += hi - res - 1;
}
return total;
}
//在有序区间[lo,hi)进行查找,并返回不大于e的最后一个元素的位置
int binSearch(vector<int>& vec, int const& e, vector<int>::size_type lo, vector<int>::size_type hi)
{
size_t count = 0;
while (lo < hi) //lo == hi时退出,区间也缩减至0
{
int mid = lo + (hi - lo >> 1); //以中点为界限,作为后续选择以左右那个子区间的条件
!(e < vec[mid]) ? hi = mid : lo = mid + 1; //深入子区间[lo ,mid) or (mid, hi),注意省略mid是符合语义的
} //循环退出时lo == hi,且此时lo刚好指向大于e的所有元素中的最小者
return --lo; //lo - 1返回不大于e的最后一个元素的位置
}
};
时间复杂度:O(m*log n)