//闭区间写法:[left, right] int left = 0, right = nums.size() - 1; //nums为vector<int> while (left <= right) { //循环终止条件为left = right + 1 int mid = (left + right) / 2; //这样写可能会出现数值溢出,可改为下面一行形式 // int mid = left + (right - left) / 2; if (target > nums[mid]) ...; //left = mid + 1; elseif (target < nums[mid]) ...; //right = mid - 1; elseif (target == nums[mid])...; //return mid; }
1 2 3 4 5 6 7 8 9
//开区间写法:[left, right) int left = 0, right = nums.size(); //nums为vector<int> while (left < right) { //循环终止条件为left = right int mid = (left + right) / 2; //这样写可能会出现数值溢出,可改为下面一行形式 // int mid = left + (right - left) / 2; if (target > nums[mid]) ...; //left = mid + 1; elseif (target < nums[mid]) ...; //right = mid; 右侧为开区间 elseif (target == nums[mid])...; //return mid,若要继续收敛,可选择是往左还是往右收敛,见下面内容 }
写对二分查找的关键是搞清楚到底应该往左收敛还是往右收敛
往左收敛:
1 2 3 4 5 6 7 8 9 10 11
intleftBound(vector<int> & nums, int target){ int left = 0, right = nums.size() - 1; while (left <= right) { int mid = (left + right) / 2; if (nums[mid] < target) left = mid + 1; elseif (nums[mid] >= target) right = mid - 1;
intleftBound(int target){ int lo = 0, hi = INT_MAX; while (lo < hi) { int mid = lo + (hi - lo) / 2; if (trailingZeroes(mid) > target) hi = mid; elseif (trailingZeroes(mid) < target) lo = mid + 1; else hi = mid;
} return lo; }
intrightBOund(int target){ int lo = 0, hi = INT_MAX; while ( lo < hi) { int mid = lo + (hi - lo) / 2; if (trailingZeroes(mid) > target) hi = mid; elseif (trailingZeroes(mid) < target) lo = mid + 1; else lo = mid + 1; } return lo - 1; }
inttrailingZeroes(int n){ int res = 0; for (int d = n; d/5 > 0; d = d/5) { res += d/5; } return res; }
classSolution { public: intminEatingSpeed(vector<int>& piles, int h){ int lo = 1; int maxValue = 0; for(int pile: piles) { maxValue = maxValue > pile ? maxValue : pile; } int hi = maxValue; while (lo < hi) { int mid = lo + (hi - lo) / 2; int times = computeTime(piles, mid); if (times < h) hi = mid; elseif (times > h) lo = mid + 1; else hi = mid; } return lo; }
intcomputeTime(vector<int>& piles, int k){ int times = 0; for (int i= 0; i <= piles.size() - 1; i++) { int pileTime = (piles[i]+ k - 1) / k; times += pileTime; } return times; } };
滑动窗口
滑动窗口技巧指维护一个窗口,不断滑动,然后更新答案。滑动窗口就是一个队列算法框架如下:
1 2 3 4 5 6 7 8 9 10 11 12 13
int left = 0, right = 0;
while (right < s.size()) { // 增大窗口 window.add(s[right]); right++;