LC209 Minimum Size Subarray Sum

Problem

Given an array of n positive integers and a positive integer s, find the minimal length of a contiguous subarray of which the sum ≥ s. If there isn’t one, return 0 instead.

Example:

1
2
3
Input: s = 7, nums = [2,3,1,2,4,3]
Output: 2
Explanation: the subarray [4,3] has the minimal length under the problem constraint.

Follow up:

If you have figured out the O(n) solution, try coding another solution of which the time complexity is O(n log n).

Think
  • Approach 1

二分法,首先计算前i个元素的和的数组sum,然后对于i在0 - n - 1之间的每一个sum[i],在sum数组中找第一个大于等于sum[i] + s的数字的下标k,此处对应的即为满足条件的子数组范围[i + 1, k]。

  • Approach 2

双指针法,首先将左指针指向0,然后每次右移一位right,判断此时能把left最多左移多少位,然后取最短的长度即可。

Code
  • Approach 1
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
int minSubArrayLen(int s, vector<int>& nums) {
int n = nums.size();
vector<int> sum(n + 1, 0);
for(int i = 1; i <= n; i++){
sum[i] = sum[i - 1] + nums[i - 1];
}
int ans = INT_MAX;
for(int i = 0; i < n; i++){
auto bound = lower_bound(sum.begin(), sum.end(), sum[i] + s);
if(bound != sum.end()){
ans = min(ans, (int)(bound - (sum.begin() + i)));
}
}
return (ans == INT_MAX) ? 0 : ans;
}
  • Approach 2
1
2
3
4
5
6
7
8
9
10
11
12
13
14
int minSubArrayLen(int s, vector<int>& nums) {
int n = nums.size();
int ans = INT_MAX;
int sum = 0;
int left = 0;
for(int i = 0; i < n; i++){
sum += nums[i];
while(sum >= s){
ans = min(ans, i - left + 1);
sum -= nums[left++];
}
}
return (ans == INT_MAX) ? 0 : ans;
}

LC230 Kth Smallest Element in a BST

Problem

Given a binary search tree, write a function kthSmallest to find the kth smallest element in it.

Example 1:

1
2
3
4
5
6
7
Input: root = [3,1,4,null,2], k = 1
3
/ \
1 4
\
2
Output: 1

Example 2:

1
2
3
4
5
6
7
8
9
Input: root = [5,3,6,2,4,null,null,1], k = 3
5
/ \
3 6
/ \
2 4
/
1
Output: 3

Follow up:
What if the BST is modified (insert/delete operations) often and you need to find the kth smallest frequently? How would you optimize the kthSmallest routine?

Constraints:

  • The number of elements of the BST is between 1 to 10^4.
  • You may assume k is always valid, 1 ≤ k ≤ BST's total elements.
Think

二分 + 递归,根据左子树的节点数目决定找左子树还是右子树

Code
1
2
3
4
5
6
7
8
9
10
int kthSmallest(TreeNode* root, int k) {
int left = getCount(root->left);
if(left == k - 1) return root->val;
else if(left < k - 1) return kthSmallest(root->right, k - left - 1);
else return kthSmallest(root->left, k);
}
int getCount(TreeNode* root){
if(!root) return 0;
return getCount(root->left) + getCount(root->right) + 1;
}

LC275 H-Index II

Problem

Given an array of citations sorted in ascending order (each citation is a non-negative integer) of a researcher, write a function to compute the researcher’s h-index.

According to the definition of h-index on Wikipedia: “A scientist has index h if h of his/her N papers have at least h citations each, and the other N − h papers have no more than h citations each.”

Example:

1
2
3
4
5
6
Input: citations = [0,1,3,5,6]
Output: 3
Explanation: [0,1,3,5,6] means the researcher has 5 papers in total and each of them had
received 0, 1, 3, 5, 6 citations respectively.
Since the researcher has 3 papers with at least 3 citations each and the remaining
two with no more than 3 citations each, her h-index is 3.

Note:

If there are several possible values for h, the maximum one is taken as the h-index.

Follow up:

  • This is a follow up problem to H-Index, where citations is now guaranteed to be sorted in ascending order.
  • Could you solve it in logarithmic time complexity?
Think

二分查找

Code
1
2
3
4
5
6
7
8
9
10
11
int hIndex(vector<int>& citations) {
int n = citations.size();
int left = 0, right = n - 1;
while(left <= right){
int mid = left + (right - left) / 2;
if(citations[mid] == n - mid) return n - mid;
else if(citations[mid] < n - mid) left = mid + 1;
else right = mid - 1;
}
return n - left;
}

LC278 First Bad Version

Problem

You are a product manager and currently leading a team to develop a new product. Unfortunately, the latest version of your product fails the quality check. Since each version is developed based on the previous version, all the versions after a bad version are also bad.

Suppose you have n versions [1, 2, ..., n] and you want to find out the first bad one, which causes all the following ones to be bad.

You are given an API bool isBadVersion(version) which will return whether version is bad. Implement a function to find the first bad version. You should minimize the number of calls to the API.

Example:

1
2
3
4
5
6
7
Given n = 5, and version = 4 is the first bad version.

call isBadVersion(3) -> false
call isBadVersion(5) -> true
call isBadVersion(4) -> true

Then 4 is the first bad version.
Think

二分查找

Code
1
2
3
4
5
6
7
8
9
int firstBadVersion(int n) {
int left = 1, right = n;
while(left < right){
int mid = left + (right - left) / 2;
if(isBadVersion(mid)) right = mid;
else left = mid + 1;
}
return left;
}

LC300 Longest Increasing Subsequence

Problem

Given an unsorted array of integers, find the length of longest increasing subsequence.

Example:

1
2
3
Input: [10,9,2,5,3,7,101,18]
Output: 4
Explanation: The longest increasing subsequence is [2,3,7,101], therefore the length is 4.

Note:

  • There may be more than one LIS combination, it is only necessary for you to return the length.
  • Your algorithm should run in O(n2) complexity.

Follow up: Could you improve it to O(n log n) time complexity?

Think
  • Approach 1

DP,dp[i] = max(dp[j] + 1) 对所有满足nums[j] < nums[i]且j < i的元素

  • Approach 2

二分,首先建立一个数组存放最长递增子序列的结果,对于每一个数字,查找这个数组中第一个大于等于当前数字的数组的下标,并用当前数字去替换(这样替换只会使得可能的最长子序列变长而不可能变短),如果没有这样的下标,则说明需要在数组的最后添加一位,最后返回该数组的总长度即可。

Code
  • Approach 1
1
2
3
4
5
6
7
8
9
10
11
12
13
14
int lengthOfLIS(vector<int>& nums) {
int n = nums.size();
vector<int> dp(n, 1);
for(int i = 1; i < n; i++){
for(int j = 0; j < i; j++){
if(nums[j] < nums[i]){
dp[i] = max(dp[i], dp[j] + 1);
}
}
}
int res = 0;
for(int cnt: dp) res = max(res, cnt);
return res;
}
  • Approach 2
1
2
3
4
5
6
7
8
9
10
11
12
13
int lengthOfLIS(vector<int>& nums) {
int n = nums.size();
vector<int> dp;
for(int num: nums){
auto i = lower_bound(dp.begin(), dp.end(), num);
if(i == dp.end()) dp.push_back(num);
else{
int idx = i - dp.begin();
dp[idx] = num;
}
}
return dp.size();
}

LC349 Intersection of Two Arrays

Problem

Given two arrays, write a function to compute their intersection.

Example 1:

1
2
Input: nums1 = [1,2,2,1], nums2 = [2,2]
Output: [2]

Example 2:

1
2
Input: nums1 = [4,9,5], nums2 = [9,4,9,8,4]
Output: [9,4]

Note:

  • Each element in the result must be unique.
  • The result can be in any order.
Think

hash set

Code
1
2
3
4
5
6
7
8
9
10
vector<int> intersection(vector<int>& nums1, vector<int>& nums2) {
unordered_set<int> map;
for(int num: nums1) map.insert(num);
unordered_set<int> res;
for(int num: nums2){
if(map.count(num)) res.insert(num);
}
vector<int> ans(res.begin(), res.end());
return ans;
}

LC350 Intersection of Two Arrays II

Problem

Given two arrays, write a function to compute their intersection.

Example 1:

1
2
Input: nums1 = [1,2,2,1], nums2 = [2,2]
Output: [2,2]

Example 2:

1
2
Input: nums1 = [4,9,5], nums2 = [9,4,9,8,4]
Output: [4,9]

Note:

  • Each element in the result should appear as many times as it shows in both arrays.
  • The result can be in any order.

Follow up:

  • What if the given array is already sorted? How would you optimize your algorithm?
  • What if nums1’s size is small compared to nums2’s size? Which algorithm is better?
  • What if elements of nums2 are stored on disk, and the memory is limited such that you cannot load all elements into the memory at once?
Think

类似上一题目,用hash map

Code
1
2
3
4
5
6
7
8
9
10
11
12
vector<int> intersect(vector<int>& nums1, vector<int>& nums2) {
unordered_map<int, int> map;
for(int num: nums1) map[num]++;
vector<int> res;
for(int num: nums2){
if(map.count(num) && map[num] > 0){
res.push_back(num);
map[num]--;
}
}
return res;
}

LC352 Data Stream as Disjoint Intervals

Problem

Given a data stream input of non-negative integers a1, a2, …, an, …, summarize the numbers seen so far as a list of disjoint intervals.

For example, suppose the integers from the data stream are 1, 3, 7, 2, 6, …, then the summary will be:

1
2
3
4
5
[1, 1]
[1, 1], [3, 3]
[1, 1], [3, 3], [7, 7]
[1, 3], [7, 7]
[1, 3], [6, 7]

Follow up:

What if there are lots of merges and the number of disjoint intervals are small compared to the data stream’s size?

Think

添加数字的时候首先求出当前数字在intervals数组中的位置,然后判断其是否和查找到的位置的前一个区间有重叠部分,如果有,则取得前一个区间,从这一个区间开始进行合并。每当遇到当前区间和val可合并,则更新start和end(表示合并后的区间),然后将当前区间移除。最后插入这个一个区间即可。

Code
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
class SummaryRanges {
public:
vector<vector<int>> intervals;
/** Initialize your data structure here. */
SummaryRanges() {

}

void addNum(int val) {
auto cmp = [](vector<int> a, vector<int> b) { return a[0] < b[0]; };
vector<int> cur = {val, val};
auto it = lower_bound(intervals.begin(), intervals.end(), cur, cmp);
if(it != intervals.begin() && (*(it - 1))[1] + 1 >= val) it--;
int start = val, end = val;
while(it != intervals.end() && val + 1 >= (*it)[0] && val - 1 <= (*it)[1]){
start = min(start, (*it)[0]);
end = max(end, (*it)[1]);
it = intervals.erase(it);
}
intervals.insert(it, {start, end});

}

vector<vector<int>> getIntervals() {
return intervals;
}
};

LC354 Russian Doll Envelopes

Problem

You have a number of envelopes with widths and heights given as a pair of integers (w, h). One envelope can fit into another if and only if both the width and height of one envelope is greater than the width and height of the other envelope.

What is the maximum number of envelopes can you Russian doll? (put one inside other)

Note:
Rotation is not allowed.

Example:

1
2
3
Input: [[5,4],[6,4],[6,7],[2,3]]
Output: 3
Explanation: The maximum number of envelopes you can Russian doll is 3 ([2,3] => [5,4] => [6,7]).
Think

将envelops数组按照第一位递增第二位递减的顺序排好,然后在所有的第二位组成的序列中查找最长递增子序列即可。因为此时只要在第二位上递增,第一位一定比上一个要小。

Code
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
struct {
bool operator()(vector<int> a, vector<int> b) const{
if(a[0] < b[0]) return true;
else if(a[0] > b[0]) return false;
else return a[1] > b[1];
}
} cmp;
int maxEnvelopes(vector<vector<int>>& envelopes) {
if(envelopes.empty()) return 0;
sort(envelopes.begin(), envelopes.end(), cmp);
vector<int> lis;
for(auto e: envelopes){
auto it = lower_bound(lis.begin(), lis.end(), e[1]);
if(it == lis.end()) lis.push_back(e[1]);
else{
int idx = it - lis.begin();
lis[idx] = e[1];
}
}
return lis.size();
}

LC363 Max Sum of Rectangle No Larger Than K

Problem

Given a non-empty 2D matrix matrix and an integer k, find the max sum of a rectangle in the matrix such that its sum is no larger than k.

Example:

1
2
3
4
Input: matrix = [[1,0,1],[0,-2,3]], k = 2
Output: 2
Explanation: Because the sum of rectangle [[0, 1], [-2, 3]] is 2,
and 2 is the max number no larger than k (k = 2).

Note:

  1. The rectangle inside the matrix must have an area > 0.
  2. What if the number of rows is much larger than the number of columns?
Think

首先对每一列,求这一列到最后某一列处的每一行的和,即sum数组,然后从上往下进行累加。首先设定一个set s存放累加和,对于每一个累加和curSum,查找第一个大于等于curSum - k的值,即这两个curSum对应的下标之间即为要求的最大的矩阵和的范围,如果存在则更新res,最后将当前累加和插入s中。

Code
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
int maxSumSubmatrix(vector<vector<int>>& matrix, int k) {
if(matrix.empty() || matrix[0].empty()) return 0;
int m = matrix.size(), n = matrix[0].size();
int res = INT_MIN;
for(int i = 0; i < n; i++){
vector<int> sum(m);
for(int j = i; j < n; j++){
for(int t = 0; t < m; t++){
sum[t] += matrix[t][j];
}
int curSum = 0;
set<int> s;
s.insert(0);
for(int a: sum){
curSum += a;
auto it = s.lower_bound(curSum - k);
if(it != s.end()) res = max(res, curSum - *it);
s.insert(curSum);
}
}
}
return res;
}

Review

二分查找的很多题目其实只是用二分查找进行了优化,很多时候是用lower_bound和upper_bound来代替二分查找,因此不需要刻意的往二分上去想,应当先想一个正常的方法,然后思考如何用二分去优化。