1. First Position of Target
class Solution {
public:
/**
* @param nums: The integer array.
* @param target: Target to find.
* @return: The first position of target. Position starts from 0.
*/
int binarySearch(vector<int> &nums, int target) {
if (nums.empty()) return -1;
int lo = 0, hi = nums.size() - 1;
// 退出的时候必需是有两个元素(或者长度为1的元素)
while (lo + 1 < hi) {
auto mid = lo + (hi - lo) / 2;
if (nums[mid] >= target) hi = mid; // 没有+1因为防止交叉
else lo = mid; // 同样没有减1
}
// 对剩下的两个元素做判断
if (target == nums[lo]) return lo;
else if (target == nums[hi]) return hi;
return -1;
}
};
2. Search a 2D matrix
class Solution {
public:
/**
* @param matrix: matrix, a list of lists of integers
* @param target: An integer
* @return: a boolean, indicate whether matrix contains target
*/
bool searchMatrix(vector<vector<int>> &matrix, int target) {
for (auto vec: matrix) {
if (binarySearch(vec, target)) return true;
}
return false;
}
bool binarySearch(const vector<int> &vec, int target) {
if (vec.empty()) return false;
int lo = 0, hi = vec.size() - 1;
while (lo + 1 < hi) {
auto mid = lo + (hi - lo) / 2;
if (vec[mid] > target) hi = mid;
else if (vec[mid] < target) lo = mid;
else return true;
}
if (vec[lo] == target || vec[hi] == target) return true;
return false;
}
};
3. Search Insert Position
class Solution {
public:
/**
* @param A: an integer sorted array
* @param target: an integer to be inserted
* @return: An integer
*/
int searchInsert(vector<int> &A, int target) {
if (A.empty()) return 0;
int lo = 0, hi = A.size() - 1;
// 锁定两个元素的区间
while (lo + 1 < hi) {
int mid = lo + (hi - lo) / 2;
if (A[mid] > target) hi = mid;
else if (A[mid] < target) lo = mid;
else return mid;
}
// 只有三种可能:
// x lo y hi z
// 1. target smaller or equal to lo, return lo
// 2. target in the middle of lo and (or equal to) hi return hi
// 3. target larger than hi return hi + 1
if (A[lo] >= target) return lo;
if (A[lo] < target && A[hi] >= target) return hi;
if (A[hi] < target) return hi + 1;
}
};
4. Search for a Range
class Solution {
public:
/**
* @param A: an integer sorted array
* @param target: an integer to be inserted
* @return: a list of length 2, [index1, index2]
*/
vector<int> searchRange(vector<int> &A, int target) {
vector<int> res{-1, -1};
if (A.empty()) return res;
int lo = 0, hi = A.size() - 1;
// search for the lower bound
while (lo + 1 < hi) {
auto mid = lo + (hi - lo) / 2;
if (target <= A[mid]) hi = mid;
else lo = mid;
}
auto lo_b = -1;
if (A[hi] == target) lo_b = hi; // 这里是找下届,因此要先hi后lo
if (A[lo] == target) lo_b = lo;
res[0] = lo_b;
// search for th upper bound
lo = 0, hi = A.size() - 1;
while (lo + 1 < hi) {
auto mid = lo + (hi - lo) / 2;
if (target >= A[mid]) lo = mid;
else hi = mid;
}
auto up_b = -1;
if (A[lo] == target) up_b = lo; // 这里找上届,要先lo后hi
if (A[hi] == target) up_b = hi;
res[1] = up_b;
return res;
}
};
5. Search in Rotated Sorted Array
class Solution {
public:
/**
* @param A: an integer rotated sorted array
* @param target: an integer to be searched
* @return: an integer
*/
int search(vector<int> &nums, int target) {
if (nums.empty()) return -1;
size_t lo = 0, hi = nums.size() - 1;
while (hi - lo > 1) {
auto mid = lo + (hi - lo) / 2;
if (target == nums[mid]) return mid;
if (target == nums[lo]) return lo;
if (target == nums[hi]) return hi; //下面要用到这个判断
if (nums[mid] < nums[hi]) { // right part
if (target > nums[mid] && target < nums[hi]) { // increasing part
lo = mid;
} else { // rotated part
hi = mid;
}
} else { // left part
if (target < nums[mid] && target > nums[lo]) { // increasing part
hi = mid;
} else { // rotated part
lo = mid;
}
}
}
if (target == nums[lo]) return lo;
if (target == nums[hi]) return hi;
return -1;
}
};
6. Search in Rotated Sorted Array II
class Solution {
public:
/**
* @param A: an integer ratated sorted array and duplicates are allowed
* @param target: An integer
* @return: a boolean
*/
bool search(vector<int> &A, int target) {
for (auto i = 0; i < A.size(); ++i) {
if (target == A[i]) return true;
}
return false;
}
};
7. Find Minimum in Rotated Sorted Array
class Solution {
public:
/**
* @param nums: a rotated sorted array
* @return: the minimum number in the array
*/
int findMin(vector<int> &nums) {
// assume the vector is not empty
size_t lo = 0, hi = nums.size() - 1;
while (lo + 1 < hi) {
auto mid = lo + (hi - lo) / 2;
// 不要用lo比较,因为如果没有rotated的话找不到第一个点
if (nums[mid] > nums[hi]) {
lo = mid;
} else if (nums[mid] < nums[hi]) {
hi = mid;
}
}
return std::min(nums[lo], nums[hi]);
}
};
8. Find Minimum in Rotated Sorted Array II
class Solution {
public:
/**
* @param nums: a rotated sorted array
* @return: the minimum number in the array
*/
int findMin(vector<int> &nums) {
size_t lo = 0, hi = nums.size() - 1;
while (lo + 1 < hi) {
auto mid = lo + (hi - lo) / 2;
if (nums[mid] < nums[hi]) { // 不能这里移动,否则会跳过最小值
hi = mid;
} else if (nums[mid] > nums[hi]) { // 相等的时候移动左边(lo)
lo = mid;
} else {
--hi;
}
}
return std::min(nums[lo], nums[hi]);
}
};
9. Find Bad Version
/**
* class SVNRepo {
* public:
* static bool isBadVersion(int k);
* }
* you can use SVNRepo::isBadVersion(k) to judge whether
* the kth code version is bad or not.
*/
class Solution {
public:
/*
* @param n: An integer
* @return: An integer which is the first bad version.
*/
int findFirstBadVersion(int n) {
int lo = 1, hi = n;
while (lo + 1 < hi) {
auto mid = lo + (hi - lo) / 2;
// 不断挤压,直到两个元素的区间(N, Y)
if (SVNRepo::isBadVersion(mid)) {
hi = mid;
} else {
lo = mid;
}
}
if (SVNRepo::isBadVersion(lo)) return lo;
if (SVNRepo::isBadVersion(hi)) return hi;
}
};
10. Find Peek Element
class Solution {
public:
/*
* @param A: An integers array.
* @return: return any of peek positions.
*/
int findPeak(vector<int>& nums) {
// the key point is to determine whether mid is on
// left side or right side
size_t lo = 0, hi = nums.size() - 1;
while (lo + 2 < hi) {
auto mid = lo + (hi - lo) / 2;
if (nums[mid] > nums[mid - 1] && nums[mid] < nums[mid + 1]) { // left side
lo = mid;
} else if (nums[mid] < nums[mid - 1] && nums[mid] > nums[mid + 1]) { // right side
hi = mid;
} else if (nums[mid] > nums[mid - 1] && nums[mid] > nums[mid + 1]) { // peek
return mid;
} else {
hi = mid; // valley, lo = mid is correct too
}
}
return lo + 1;
}
};
11. Sqrt(x)
class Solution {
public:
/**
* @param x: An integer
* @return: The sqrt of x
*/
int sqrt(int x) {
if (x == 1) return 1;
long lo = 0, hi = x / 2; // 注意这里的类型防止溢出
while (lo + 1 < hi) {
auto mid = lo + (hi - lo) / 2;
if (mid * mid > x) {
hi = mid;
} else if (mid * mid < x) {
lo = mid;
} else {
return mid;
}
}
// 先hi后lo判断
if (hi * hi <= x) return hi;
if (lo * lo <= x) return lo;
}
};
12. Longest Increasing Subsequence
跟binary search 貌似没什么关系
class Solution {
public:
/**
* @param nums: An integer array
* @return: The length of LIS (longest increasing subsequence)
*/
int longestIncreasingSubsequence(vector<int> &nums) {
// corner case
if (nums.empty()) return 0;
if (nums.size() == 1) return 1;
// initialize the seq-length started from each element to 1
vector<int> lens(nums.size(), 1);
// scan from end to beginning, increasing the length
for (int i = nums.size() - 2; i >= 0; --i) {
auto maxLen = 0;
for (int j = i + 1; j < nums.size(); ++j) {
if (nums[j] > nums[i] && lens[j] > maxLen) {
maxLen = lens[j];
}
}
lens[i] += maxLen;
}
return *std::max_element(lens.begin(), lens.end());
}
};
13. wood cut
class Solution {
public:
/**
* @param L: Given n pieces of wood with length L[i]
* @param k: An integer
* @return: The maximum length of the small pieces
*/
int woodCut(vector<int> &L, int k) {
if (L.empty()) return 0;
int res = *std::max_element(L.begin(), L.end());
if (doCut(L, res) >= k) return res;
// use hi as the outter loop
int lo = 1, hi = res;
while (lo + 1 < hi) {
auto mid = lo + (hi - lo) / 2;
auto cnt = doCut(L, mid);
if (cnt >= k) {
lo = mid;
} else if (cnt < k) {
hi = mid;
}
}
if (doCut(L, hi) >= k) return hi;
if (doCut(L, lo) >= k) return lo;
return 0;
}
// calculate number of segments after cut by len
int doCut(const vector<int> &L, int len) {
int cnt = 0;
for (auto l: L) {
cnt += l / len;
}
return cnt;
}
};
14. Interval Minimum Number
- TLE
/**
* Definition of Interval:
* classs Interval {
* int start, end;
* Interval(int start, int end) {
* this->start = start;
* this->end = end;
* }
* }
*/
class Solution {
public:
/**
* @param A: An integer array
* @param queries: An query list
* @return: The result list
*/
vector<int> intervalMinNumber(vector<int> &A, vector<Interval> &queries) {
vector<int> res;
if (queries.empty()) return res;
for (auto query: queries) {
res.push_back(calcMin(A, query.start, query.end));
}
}
// notice the index below, it's exactly the binary search
// (0, 2)
// (0, 1) (1, 2)
// (0, 0) (1, 1) (2, 2)
int calcMin(const vector<int> &A, int lo, int hi) {
if (lo + 1 >= hi) return std::min(A[lo], A[hi]);
auto mid = lo + (hi - lo) / 2;
return std::min(
calcMin(A, lo, mid),
calcMin(A, mid, hi));
}
};
- MLE
/**
* Definition of Interval:
* classs Interval {
* int start, end;
* Interval(int start, int end) {
* this->start = start;
* this->end = end;
* }
* }
*/
class Solution {
public:
/**
* @param A: An integer array
* @param queries: An query list
* @return: The result list
*/
vector<int> intervalMinNumber(vector<int> &A, vector<Interval> &queries) {
vector<int> res;
if (queries.empty()) return res;
vector<int> cache(A.size() * A.size(), INT_MAX);
//buildMin(A, 0, A.size() - 1, cache);
for (auto query: queries) {
if (cache[hash(A, query.start, query.end)] == INT_MAX) {
buildMin(A, query.start, query.end, cache);
}
res.push_back(cache[hash(A, query.start, query.end)]);
}
}
int buildMin(const vector<int> &A, int lo, int hi,
vector<int> &cache) {
if (lo + 1>= hi) {
cache[hash(A, lo, lo)] = A[lo];
cache[hash(A, hi, hi)] = A[hi];
cache[hash(A, lo, hi)] = std::min(A[lo], A[hi]);
return std::min(A[lo], A[hi]);
}
auto mid = lo + (hi - lo) / 2;
auto min = std::min(buildMin(A, lo, mid, cache),
buildMin(A, mid, hi, cache));
cache[hash(A, lo, hi)] = min;
return min;
}
int hash(const vector<int> &A, int lo, int hi) {
return lo * A.size() + hi;
}
// notice the index below, it's exactly the binary search
// (0, 2)
// (0, 1) (1, 2)
// (0, 0) (1, 1) (2, 2)
int calcMin(const vector<int> &A, int lo, int hi) {
if (lo + 1 >= hi) return std::min(A[lo], A[hi]);
auto mid = lo + (hi - lo) / 2;
return std::min(
calcMin(A, lo, mid),
calcMin(A, mid, hi));
}
};
- AC
class Solution {
struct Node {
int lo, hi, min;
struct Node *l, *r;
};
public:
/**
* @param A: An integer array
* @param queries: An query list
* @return: The result list
*/
vector<int> intervalMinNumber(vector<int> &A, vector<Interval> &queries) {
vector<int> res;
if (queries.empty()) return res;
struct Node *root = buildMinTree(A, 0, A.size() - 1);
for (auto query: queries) {
res.push_back(searchMinTree(root, query.start, query.end));
}
return res;
}
Node *buildMinTree(const vector<int> &A, int lo, int hi) {
if (lo == hi) {
return new Node{lo, hi, A[lo], nullptr, nullptr};
}
auto mid = lo + (hi - lo) / 2;
auto l = buildMinTree(A, lo, mid);
auto r = buildMinTree(A, mid + 1, hi); // 不加1会导致(0, 1)区间无线循环
return new Node{lo, hi, std::min(l->min, r->min), l, r};
}
int searchMinTree(Node *root, int lo, int hi) {
// 找区间最小值,可以完全匹配是因为下边的mid + 1操作
if (root->lo == lo && root->hi == hi) return root->min;
auto mid = root->lo + (root->hi - root->lo) / 2;
// 不过根节点的两种情况
if (lo >= mid + 1) return searchMinTree(root->r, lo, hi);
else if (hi <= mid) return searchMinTree(root->l, lo, hi);
// 需要过根节点进行搜索
return std::min(searchMinTree(root->l, lo, mid),
searchMinTree(root->r, mid + 1, hi));
}
};
15. Interval Sum
/**
* Definition of Interval:
* classs Interval {
* int start, end;
* Interval(int start, int end) {
* this->start = start;
* this->end = end;
* }
* }
*/
class Solution {
struct Node {
int lo, hi;
long long sum; // !!
Node *l, *r;
};
public:
/**
* @param A: An integer list
* @param queries: An query list
* @return: The result list
*/
vector<long long> intervalSum(vector<int> &A, vector<Interval> &queries) {
vector<long long> res;
if (queries.empty()) return res;
auto root = buildSumTree(A, 0, A.size() - 1);
for (auto query: queries) {
res.push_back(searchSumTree(root, query.start, query.end));
}
return res;
}
Node *buildSumTree(const vector<int> &A, int lo, int hi) {
if (lo == hi) return new Node{lo, hi, A[lo], nullptr, nullptr};
auto mid = lo + (hi - lo) / 2;
auto l = buildSumTree(A, lo, mid);
auto r = buildSumTree(A, mid + 1, hi);
return new Node{lo, hi, l->sum + r->sum, l, r};
}
long long searchSumTree(Node *root, int lo, int hi) {
if (root->lo == lo && root->hi == hi) return root->sum;
auto mid = root->lo + (root->hi - root->lo) / 2;
if (lo >= mid + 1) return searchSumTree(root->r, lo, hi);
if (hi <= mid) return searchSumTree(root->l, lo, hi);
return searchSumTree(root->l, lo, mid) +
searchSumTree(root->r, mid + 1, hi);
}
};
16. Interval Sum II
class Solution {
struct Node {
int lo, hi;
long long sum;
Node *l, *r;
};
Node *root;
public:
/* you may need to use some attributes here */
/*
* @param A: An integer array
*/
Solution(vector<int> A) : root(nullptr) {
if (!A.empty()) {
root = build(A, 0, A.size() - 1);
}
}
Node *build(const vector<int> &A, int lo, int hi) {
if (lo == hi) return new Node{lo, hi, A[lo], nullptr, nullptr};
auto mid = lo + (hi - lo) / 2;
auto l = build(A, lo, mid);
auto r = build(A, mid + 1, hi);
return new Node{lo, hi, l->sum + r->sum, l, r};
}
long long query(Node * root, int lo, int hi) {
if (root->lo == lo && root->hi == hi) return root->sum;
auto mid = root->lo + (root->hi - root->lo) / 2;
if (lo >= mid + 1) return query(root->r, lo, hi);
if (hi <= mid) return query(root->l, lo, hi);
return query(root->l, lo, mid) + query(root->r, mid + 1, hi);
}
long long modify(Node *root, int index, int val) {
if (root->lo == index && root->hi == index) {
auto diff = val - root->sum;
root->sum = val;
return diff;
}
auto diff = 0;
auto mid = root->lo + (root->hi - root->lo) / 2;
// 只用更新一个分支
if (index >= mid + 1) diff = modify(root->r, index, val);
if (index <= mid) diff = modify(root->l, index, val);
root->sum += diff;
return diff;
}
/*
* @param start: An integer
* @param end: An integer
* @return: The sum from start to end
*/
long long query(int start, int end) {
if (!root) return 0;
return query(root, start, end);
}
/*
* @param index: An integer
* @param value: An integer
* @return: nothing
*/
void modify(int index, int value) {
if (root) modify(root, index, value);
}
};
17. Count of Smaller Number
class SolutionV1 {
public:
/**
* @param A: An integer array
* @param queries: The query list
* @return: The number of element in the array that are smaller that the given integer
*/
vector<int> countOfSmallerNumber(vector<int> &A, vector<int> &queries) {
vector<int> res;
if (A.empty()) {
res.assign(queries.size(), 0);
return res;
}
sort(A.begin(), A.end());
for (auto query: queries) {
res.push_back(search(A, query));
}
return res;
}
int search(const vector<int> &nums, int target) {
size_t lo = 0, hi = nums.size() - 1;
while (lo + 1 < hi) {
auto mid = lo + (hi - lo) / 2;
if (target <= nums[mid]) {
hi = mid;
} else {
lo = mid;
}
}
// 实际上是在找插入的位置
if (target <= nums[lo]) return lo;
if (target > nums[lo] && target <= nums[hi]) return hi;
if (target > nums[hi]) return hi + 1;
return 0;
}
};
18. Count of Smaller Number II
class Solution {
struct Node {
int val;
int cnt;
Node *l, *r;
};
public:
/**
* @param A: an integer array
* @return: A list of integers includes the index of the first number and the index of the last number
*/
vector<int> countOfSmallerNumberII(vector<int> &A) {
// 1. build a binary tree, for each node instered into the node
// - if the val to be instered is on the right node, which is easy
// to handle, just equals to 1 + cnt(root);
// - if the val is equal to the root, just update the root count
// - if the val is small than the root count, search to the right pos
// and pass the parent's cnt into current node
// NOTICE: this is a top down approach, which means path is required
vector <int> temp;
vector<int> res;
for (int i = 0; i < A.size(); i++) {
auto itr = lower_bound(temp.begin(), temp.end(), A[i]);
int count = itr - temp.begin();
res.push_back(count);
temp.insert(itr, A[i]);
}
}
};
19. Divided Two Integers
class Solution {
public:
/**
* @param dividend: the dividend
* @param divisor: the divisor
* @return: the result
*/
enum Sign {
POS,
NEG
};
int divide(int dd, int d) {
long long dividend = dd;
long long divisor = d;
if (divisor == 0) return INT_MAX;
if (dividend == INT_MIN && divisor == -1) return INT_MAX;
if (dividend == 0) return 0;
enum Sign sign = POS;
if (dividend < 0 && divisor > 0) sign = NEG;
if (dividend >0 && divisor < 0) sign = NEG;
dividend = std::abs(dividend);
divisor = std::abs(divisor);
// max index
// q = y / x
// y = x * q
// q = qi * 2 ^ i + ... + q0 * 2 ^ 0
int i = 0;
while ((divisor << (i + 1)) <= dividend) ++i;
int res = 0;
while (dividend > 0 && i >= 0) {
if (dividend >= (divisor << i)) {
dividend -= divisor << i;
res += 1 << i;
}
i--;
}
return sign == NEG ? -res : res;
}
};
20. Pow(x, n)
class Solution {
#include <float.h>
public:
/*
* @param x: the base number
* @param n: the power number
* @return: the result
*/
double myPow(double x, int n) {
if (n == 0) return 1;
int neg = 1;
if (n < 0) {
neg = -1;
n = -n;
}
auto res = doPow(x, n);
if (neg == -1) res = 1. / res;
return res;
}
double doPow(double x, int n) {
if (n == 0) return 1;
auto res = doPow(x, n / 2);
return (n % 2) ? (x * res * res) : (res * res);
}
};
21. classical binary search
class Solution {
public:
/*
* @param nums: An integer array sorted in ascending order
* @param target: An integer
* @return: An integer
*/
int findPosition(vector<int> &nums, int target) {
if (nums.empty()) return -1;
size_t lo = 0, hi = nums.size() - 1;
while (lo + 1 < hi) {
auto mid = lo + (hi - lo) / 2;
if (target == nums[mid]) return mid;
else if (target > nums[mid]) {
lo = mid;
} else {
hi = mid;
}
}
return -1;
}
};
22. Find K Closet Elements
class Solution {
public:
/**
* @param A: an integer array
* @param target: An integer
* @param k: An integer
* @return: an integer array
*/
vector<int> kClosestNumbers(vector<int> &A, int target, int k) {
// 1. search insert position of target
// 2. merge k elements on left and k elements on right by their difference
if (A.empty()) return vector<int>{};
auto pos = insertPos(A, target);
auto lpos = pos, rpos = pos + 1;
vector<int> res;
while (lpos >= 0 && rpos <= (A.size() - 1) && res.size() < k) {
auto ldiff = abs(A[lpos] - target);
auto rdiff = abs(A[rpos] - target);
if (ldiff == rdiff) {
// store the smaller of the two
if (A[lpos] < A[rpos]) {
res.push_back(A[lpos--]);
} else {
res.push_back(A[rpos++]);
}
} else if (ldiff > rdiff) {
res.push_back(A[rpos++]);
} else {
res.push_back(A[lpos--]);
}
}
while (lpos >= 0 && res.size() < k) {
res.push_back(A[lpos--]);
}
while (rpos <= (A.size() - 1) && res.size() < k) {
res.push_back(A[rpos++]);
}
return res;
}
int insertPos(const vector<int> &A, int target) {
size_t lo = 0, hi = A.size() - 1;
while (lo + 1 < hi) {
auto mid = lo + (hi - lo) / 2;
if (target == A[mid]) return mid;
else if (target > A[mid]) lo = mid;
else hi = mid;
}
return min(lo, hi);
}
};
23. Intersection of two arrays
class Solution {
public:
/*
* @param nums1: an integer array
* @param nums2: an integer array
* @return: an integer array
*/
vector<int> intersection(vector<int> nums1, vector<int> nums2) {
if (nums1.empty() || nums2.empty()) return vector<int>{};
set<int> res;
sort(nums2.begin(), nums2.end());
for (int n1: nums1) {
if (binarySearch(nums2, n1)) {
res.insert(n1);
}
}
vector<int> r(res.begin(), res.end());
return r;
}
bool binarySearch(const vector<int> &nums, int target) {
size_t lo = 0, hi = nums.size() - 1;
while (lo + 1 < hi) {
auto mid = lo + (hi - lo) / 2;
if (nums[mid] == target) return true;
else if (nums[mid] < target) lo = mid;
else hi = mid;
}
if (nums[lo] == target || nums[hi] == target) return true;
return false;
}
};
24. Intersection of two arrays II
class Solution {
public:
/*
* @param nums1: an integer array
* @param nums2: an integer array
* @return: an integer array
*/
vector<int> intersection(vector<int> nums1, vector<int> nums2) {
if (nums1.empty() || nums2.empty()) return vector<int>{};
sort(nums1.begin(), nums1.end());
sort(nums2.begin(), nums2.end());
vector<int> res;
int p1 = 0, p2 = 0;
while (p1 < nums1.size() && p2 < nums2.size()) {
if (nums1[p1] == nums2[p2]) {
res.push_back(nums1[p1++]);
++p2;
} else if (nums1[p1] > nums2[p2]) {
++p2;
} else {
++p1;
}
}
return res;
}
};
25. guess number
// Forward declaration of guess API.
// @param num, your guess
// @return -1 if my number is lower, 1 if my number is higher, otherwise return 0
int guess(int num);
class Solution {
public:
/**
* @param n an integer
* @return the number you guess
*/
int guessNumber(int n) {
int lo = 0, hi = n;
while (lo + 1 < hi) {
auto mid = lo + (hi - lo) / 2;
auto res = guess(mid);
if (res == 0) return mid;
else if (res > 0) lo = mid;
else hi = mid;
}
if (guess(lo) == 0) return lo;
if (guess(hi) == 0) return hi;
}
};
26. Find the Duplicate Number
class Solution {
public:
/**
* @param nums: an array containing n + 1 integers which is between 1 and n
* @return: the duplicate one
* O(1) space: no hash, no array, no tree
* O(n^2) time: no brute force, consider binary search
* special condition: numbers 1...n
*/
int findDuplicate(vector<int> &nums) {
int lo = 1, hi = nums.size() - 1; // 1...n
while (lo < hi) {
int mid = lo + (hi - lo) / 2;
int cnt = 0; // statistics numbers samller than mid
for (auto num: nums) {
if (num <= mid) {
++cnt;
}
}
// there are `mid` number smaller than mid in normal sequence
// if there are `cnt` numbers larger than mid, then the duplicated
// number is in the hi...size part
if (cnt > mid) hi = mid;
else lo = mid + 1;
}
return lo;
}
};
27. Maximum Average Subarray II
class Solution {
public:
/*
* @param nums: an array with positive and negative numbers
* @param k: an integer
* @return: the maximum average
*/
/*
(nums[i]+nums[i+1]+…+nums[j])/(j-i+1)>x
=>nums[i]+nums[i+1]+…+nums[j]>x*(j-i+1)
=>(nums[i]-x)+(nums[i+1]-x)+…+(nums[j]-x)>0
*/
double maxAverage(vector<int> &nums, int k) {
double lo = *std::min_element(nums.begin(), nums.end());
double hi = *std::max_element(nums.begin(), nums.end());
while (hi - lo > 10e-7) {
double mid = (lo + hi) / 2;
if (check(nums, k, mid)) lo = mid;
else hi = mid;
}
return (lo + hi) / 2;
}
// k is the sliding window
// S(i) = S(i-1) + Num(i) - Num(i - k + 1)
double check(const vector<int> &nums, int k, double mid) {
double sum = 0.0;
for (int i = 0; i < k; i++)
sum += nums[i] - mid;
double maxSum = sum, prev = nums[0] - mid;
for (int i = k; i < nums.size(); i++) {
sum = sum - nums[i - k] + nums[i];
maxSum = std::max(maxSum, std::max(sum, sum + prev));
prev = std::max((double)nums[i - k + 1], nums[i - k + 1] + prev) - mid;
}
return maxSum >= 0;
}
};