class Solution {
public:
int search(vector<int>& nums, int target) {
int n = nums.size();
int left = 0, right = n - 1; // create 2 pointers
while(left <= right){ // ⬇️⬇️ key point
int mid = left + (right - left) / 2; // (left + right) / 2 maybe out of range
if(nums[mid] == target) return mid; // find the target
else if(nums[mid] < target) left = mid + 1; // target in the right half array
else right = mid - 1; // target in the left half array
}
return -1; // no target in the array
}
};
class Solution {
public:
int searchInsert(vector<int>& nums, int target) {
int n = nums.size();
int left = 0, right = n - 1; // create 2 pointers
while(left <= right){
int mid = left + (right - left) / 2; // ‼️ commonly seen in binary search
if(nums[mid] == target) return mid; // find the target
else if(nums[mid] < target) left = mid + 1;
else right = mid - 1;
}
return left; // no target in the array thus return left index
}
};
34. Find First and Last Position of Element in Sorted Array
1️⃣最容易想到的方法,但可能有一些时间复杂度错误,因为是O(log N + K)
class Solution {
public:
vector<int> searchRange(vector<int>& nums, int target) {
int n = nums.size();
int left = 0, right = n - 1; // create 2 pointers
while(left <= right){
int mid = left + (right - left) / 2; // find the area of the target might exist
if(nums[mid] < target){
left = mid + 1;
}
else if(nums[mid] > target){
right = mid - 1;
}
else { // case when target in the area
while(nums[left] < target) left ++; // move the pointer to the right place
while(nums[right] > target) right --;
return {left, right};
}
}
return {-1, -1}; // no target in the array
}
};
2️⃣用lower_bound然后类型转换
class Solution {
public:
vector<int> searchRange(vector<int>& nums, int target) {
auto left = lower_bound(nums.begin(), nums.end(), target); // nums[left] >= target
auto right = lower_bound(nums.begin(), nums.end(), target + 1); // nums[right] >= target + 1
if(left != nums.end() && *left == target){
return {static_cast<int>(left - nums.begin()), static_cast<int>(right - nums.begin() - 1)};
// static_cast<int> 是类型转换符, 将迭代器转换为int型
// conversion operator, convert iterator to integer type
}
else return {-1, -1};
}
};
3️⃣手搓lower_bound:
class Solution {
public:
int lower_bound(vector<int>& nums, int target){
int left = 0, right = nums.size() - 1;
while(left <= right){ // keep moving the pointers until left points the lower_bound
int mid = left + (right - left) / 2;
if(nums[mid] < target) left = mid + 1;
else right = mid - 1;
}
return left;
}
vector<int> searchRange(vector<int>& nums, int target) {
int l = lower_bound(nums, target);
int r = lower_bound(nums, target + 1) - 1; // r points the upper_bound
if(l < nums.size() && nums[l] == target) return {l, r}; // check whether target exists
else return {-1, -1};
}
};
刚拿到题还有点棘手说实话....……一直爆超时,画个图思路清晰多了
class Solution {
public:
int mySqrt(int x) {
if(x == 0) return x; // specail case
int left = 1, right = x;
while(left <= right){ // binary search
int mid = left + (right - left) / 2; // avoid overflow
if(mid <= x / mid && (mid + 1) > x / (mid + 1)) return mid; // hit the range
else if(x / mid < mid) right = mid - 1;
else left = mid + 1;
}
return -1; // impossible case;
}
};
补充:下面是一个二分答案的板子,突然想起了编程有关数论的题目了.....顺便复习一下好了: 想法是一致的,不过设置了一个精度范围
#include<bits/stdc++.h>
using namespace std;
double sq(double x){ //二分答案
double left = 0;
double right = x;
double eps = 1e-10; //设置误差,表示10的-10次方
while(left + eps < right){
double mid = left + (right - left) / 2;
if(mid * mid < x) left = mid; // 浮点数的二分有点不同
else right = mid;
}
return left;
}
int main(){
double x = 5.0;
cout << sq(x) << endl;
return 0;
}
// sqrt(2) ≈ 1.41421
class Solution {
public:
bool isPerfectSquare(int num) {
long left = 1, right = num; // binary search
while(left <= right){
long mid = left + (right - left) / 2;
long q = mid * mid;
if(q == num) return true;
else if(q > num) right = mid - 1;
else left = mid + 1;
}
return false; // impossible case
}
};
Solution 1 : # Tow pointers && # Brute force
class Solution {
public:
int removeElement(vector<int>& nums, int val) { // 2 loops Brute force
int size = nums.size();
for(int i = 0; i < size; i++){ // pointer i is to find the val in the array
if(nums[i] == val){
for(int j = i + 1; j < size; j++){ // pointer j is to move the remaining array forward
nums[j - 1] = nums[j];
}
i --; // put i into the right location
size --; // remove the val in the array thus size --
}
}
return size;
}
};
Solution 2 : # Slow & fast pointers
class Solution {
public:
int removeElement(vector<int>& nums, int val) {
int slow = 0;
for(int fast = 0; fast < nums.size(); fast++){ // fast pointer is to traverse the array
if(nums[fast] != val){
nums[slow++] = nums[fast]; // slow pointer is to renew the array
}
}
return slow;
}
};
Feedback : 😠我怎么第三遍刷这道题的时候想不到这个快慢指针呢......Damn🤬
26. Remove Duplicates from Sorted Array
Solution 1 : # Fast & slow pointers, 注意快指针的起始位置
class Solution {
public:
int removeDuplicates(vector<int>& nums) {
int n = nums.size();
int slow = 0;
for(int fast = 1; fast < n; fast++){ // fast pointer is always in front of slow pointer
if(nums[fast] != nums[slow]) nums[++slow] = nums[fast]; // if not the same, slow pointer moves
}
slow++; // resize the nums
return slow;
}
};
Solution 2 : # Unique
class Solution {
public:
int removeDuplicates(vector<int>& nums) {
auto q = unique(nums.begin(), nums.end());
nums.erase(q, nums.end());
return nums.size();
}
};
Solution 1 : # Tow pointers
class Solution {
public:
void moveZeroes(vector<int>& nums) {
int n = nums.size();
int p1 = 0; // p1 points the location for exchanging the non-zero element
for(int p2 = 0; p2 < n; p2++){ // p2 is to find the non-zero element
if(nums[p2] != 0){
swap(nums[p1], nums[p2]);
p1++; // move p1 afterward if changed
}
}
}
};
Solution 2 : # Brute force
class Solution {
public:
void moveZeroes(vector<int>& nums) {
int n = nums.size();
int j = 0;
for(int i = 0; i < n; i++){ // move all non-zero element forward in relative order
if(nums[i] != 0) nums[j++] = nums[i];
}
for(j; j < n; j++) nums[j] = 0; // repalce the left elements with 0
}
};
977. Squares of a Sorted Array
Solution 1 : # Brute force || 直接根据题意的意思暴力一下就可以了,但是时间复杂度是O(log N)级别的
class Solution {
public:
vector<int> sortedSquares(vector<int>& nums) {
int n = nums.size();
for(int i = 0; i < n; i++) nums[i] *= nums[i];
sort(nums.begin(), nums.end());
return nums;
}
};
Solution 2 : # Tow pointers || 绝对值的大小从两端不断向中间递减,根据这个规律优化时间复杂度
class Solution {
public:
vector<int> sortedSquares(vector<int>& nums) {
int n = nums.size();
int left = 0, right = n - 1; // tow pointers
vector<int> result(n, -1);
while(left <= right){
int l = nums[left] * nums[left];
int r = nums[right] * nums[right];
int k;
if(l >= r){
k = l;
left++;
}
else{
k = r;
right--;
}
result[--n] = k; // assign values to the elements from the end to the beginning
} // in this way, we don't have to reverse the array
return result;
}
};
209. Minimum Size Subarray Sum
Solution : # Sliding window
class Solution {
public:
int minSubArrayLen(int target, vector<int>& nums) {
int sum = 0;
int start = 0; // the start of the sliding window
int result = INT_MAX;
int subL = 0; // length of the subarray
for(int end = 0; end < nums.size(); end++){
sum += nums[end];
while(sum >= target){ // when it meets the requirement, move the sliding window
subL = end - start + 1; // the length of current subarray
result = min(result, subL); // refresh the result
sum -= nums[start++]; // move the start of the sliding window
}
}
return result == INT_MAX ? 0 : result; // if the result is changed, then the subarray exists
}
};
Solution : # Sliding window
class Solution {
public:
int totalFruit(vector<int>& fruits) {
unordered_map<int, int> basket;
int left = 0, right = 0, ans = 0;
while(right < fruits.size()){
basket[fruits[right]]++; // put the fruit into the basket
while(basket.size() > 2){ // if there are over 2 kinds of fruits in the basket
basket[fruits[left]]--;
if(basket[fruits[left]] == 0){
basket.erase(fruits[left]); // put the left kind of fruits is out of basket
}
left++;
}
ans = max(ans, right - left + 1);
right++;
}
return ans;
}
};
下面是一个暴力的代码,但是O(N^2)的时间复杂度会超时
class Solution {
public:
int totalFruit(vector<int>& fruits) {
int ans = 0;
unordered_map<int, int> count;
for(int left = 0; left < fruits.size(); left++){
count.clear();
for(int right = left; right < fruits.size(); right++){
count[fruits[right]]++;
if(count.size() > 2) break; //超出两种水果就break
ans = max(ans, right - left + 1);
}
}
return ans;
}
};
// 70 / 91 testcases passed
Solution: # Simulation
class Solution {
public:
vector<vector<int>> generateMatrix(int n) {
vector<vector<int>> ans(n, vector<int>(n, 0)); // n*n matrix
int loop = n / 2;
int sx = 0, sy = 0; // starting location when each loops begain
int mid = n / 2; // when n is odd, we need to fill the mid location in the matrix
int i , j; // to record current positon when looping
int offset = 1; // when each loop ends, offset + 1
int count = 1; // the number to be fiiled in the matrix
while(loop--){
i = sx, j = sy;
for(; j < n - offset; j++) ans[i][j] = count++; // fill the upmost line
for(; i < n - offset; i++) ans[i][j] = count++; // fill the rightmost line
for(; j > sy; j--) ans[i][j] = count++; // fill the downmost line
for(; i > sx; i--) ans[i][j] = count++; // fill the leftmost line
sx++; // when each loop ends, change the starting location & offset
sy++;
offset++;
}
if(n % 2) ans[mid][mid] = count; // if n is odd, fill the center location
return ans;
}
};
Solution: # Simulation
class Solution {
public:
vector<int> spiralOrder(vector<vector<int>>& matrix) {
vector<int> ans;
int m = matrix.size(); // line
int n = matrix[0].size(); // column
if(m == 0 || n == 0) return ans;
int left = 0, right = n - 1, top = 0, bottom = m - 1;
while(left <= right && top <= bottom){
for(int j = left; j <= right; j++) ans.push_back(matrix[top][j]);
for(int i = top + 1; i <= bottom; i++) ans.push_back(matrix[i][right]);
if(top < bottom && left < right){
for(int j = right - 1; j > left; j--) ans.push_back(matrix[bottom][j]);
for(int i = bottom; i > top; i--) ans.push_back(matrix[i][left]);
}
top++;
bottom--;
left++;
right--;
}
return ans;
}
};