目录
1--二分查找法
2--二分查找法进阶
2-1--寻找第一个等于目标值的位置
2-2--寻找最后一个等于目标值的位置
3--双指针算法
3-1--快慢指针移除元素
3-2--有序数组的平方
4--滑动窗口算法
5--循环不变量
1--二分查找法
二分查找法用于有序数组的元素查找,一般可以分为左闭右闭写法、左闭右开写法、左开右闭写法,其中左闭右闭写法最常用;
#include <iostream>
#include <vector>class Solution {
public:// 左闭右闭写法int search1(std::vector<int>& arr, int target){int left = 0, right = arr.size() - 1;while(left <= right){ // 因为是左闭右闭写法,当left == right时[left, right]也是合法的,因此left <= rightint mid = left + (right - left) / 2;if(arr[mid] > target){right = mid - 1;}else if(arr[mid] < target){left = mid + 1;}else return arr[mid];}return -1; // 表示未找到}// 左闭右开写法int search2(std::vector<int>& arr, int target){int left = 0, right = arr.size();while(left < right){ // 因为是左闭右开写法,当left == right时[left, right)是非法的,因此left < rightint mid = left + (right - left) / 2;if(arr[mid] > target){right = mid; // 右开}else if(arr[mid] < target){left = mid + 1; // 左闭}else return arr[mid];}return -1; // 表示未找到}// 左开右闭写法int search3(std::vector<int>& arr, int target){int left = -1, right = arr.size() - 1;while(left < right){ // 因为是左闭右开写法,当left == right时(left, right]是非法的,因此left < rightint mid = left + (right - left) / 2;if(arr[mid] > target){right = mid - 1; // 右闭}else if(arr[mid] < target){left = mid; // 左开}else return arr[mid];}return -1; // 表示未找到}
};int main(int argc, char *argv[]){std::vector<int> test = {1, 2, 3, 4, 5, 6, 7, 8, 9};int target = 2;Solution S1;int res1 = S1.search1(test, target);int res2 = S1.search2(test, target);int res3 = S1.search3(test, target);std::cout << res1 << ", " << res2 << ", " << res3 << std::endl;return 0;
}
2--二分查找法进阶
2-1--寻找第一个等于目标值的位置
等于号 = 放在哪个条件判断的依据:当 arr[mid] == target 时,应该往哪一边继续二分寻找;
#include <iostream>
#include <vector>class Solution {
public:// 左闭右闭写法int search1(std::vector<int>& arr, int target){int left = 0, right = arr.size() - 1;int res = -1;while(left <= right){int mid = left + (right - left) / 2;if(arr[mid] >= target){res = mid; // 记录可能的位置right = mid - 1;}else if(arr[mid] < target){left = mid + 1;}}if(res == -1 || arr[res] != target) return -1; //未找到targetreturn res;}};int main(int argc, char *argv[]){std::vector<int> test = {1, 2, 2, 2, 3, 3, 4};int target = 2;Solution S1;int res1 = S1.search1(test, target);std::cout << res1 << std::endl;return 0;
}
2-2--寻找最后一个等于目标值的位置
等于号 = 放在哪个条件判断的依据:当 arr[mid] == target 时,应该往哪一边继续二分寻找;
#include <iostream>
#include <vector>class Solution {
public:// 左闭右闭写法int search1(std::vector<int>& arr, int target){int left = 0, right = arr.size() - 1;int res = -1;while(left <= right){int mid = left + (right - left) / 2;if(arr[mid] > target){right = mid - 1;}else if(arr[mid] <= target){res = mid; // 记录可能的位置left = mid + 1;}}if(res == -1 || arr[res] != target) return -1; //未找到targetreturn res;}};int main(int argc, char *argv[]){std::vector<int> test = {1, 2, 2, 2, 3, 3, 4};int target = 2;Solution S1;int res1 = S1.search1(test, target);std::cout << res1 << std::endl;return 0;
}
3--双指针算法
3-1--快慢指针移除元素
#include <iostream>
#include <vector>class Solution {
public:int removeElement(std::vector<int>& nums, int val) {int slow = 0, fast = 0;while(fast < nums.size()){if(nums[fast] != val){nums[slow] = nums[fast];slow++;fast++;}else{fast++;}}return slow;}
};int main(int argc, char argv[]){// nums = [3,2,2,3], val = 3std::vector<int> test = {3, 2, 2, 3};int val = 3;Solution S1;int res = S1.removeElement(test, val);std::cout << res << std::endl;
}
3-2--有序数组的平方
主要思路:
由于数组包含负数,则平方后的数组符合:大→小→大的排列规律;可以利用双指针算法从两端向中间遍历,取最大值放在结果数组(提前开辟);
#include <iostream>
#include <vector>class Solution {
public:std::vector<int> sortedSquares(std::vector<int>& nums) {std::vector<int> res(nums.size(), 0);int i = 0, j = nums.size() - 1, k = nums.size() - 1;while(i <= j){if(nums[i]*nums[i] > nums[j]*nums[j]){res[k] = nums[i]*nums[i];k--;i++;}else{res[k] = nums[j]*nums[j]; k--;j--;}}return res;}
};int main(int argc, char argv[]){// nums = [-4,-1,0,3,10]std::vector<int> test = {-4, -1, 0, 3, 10};Solution S1;std::vector<int> res = S1.sortedSquares(test);for(auto v : res) std::cout << v << " ";return 0;
}
4--滑动窗口算法
主要思路:
维护一个滑动窗口,当满足滑动窗口内元素和 》= target 时,判断是否更新最小长度;
#include <iostream>
#include <vector>class Solution {
public:int minSubArrayLen(int target, std::vector<int>& nums) {int i = 0, j = 0;int sum = 0, min_len = nums.size() + 1;while(j < nums.size()){sum += nums[j];while(sum >= target){min_len = std::min(min_len, j - i + 1);//缩小滑动窗口范围sum = sum - nums[i];i++; }j++; //寻找下一个满足条件的滑动窗口}return min_len == nums.size() + 1 ? 0 : min_len;}
};int main(int argc, char argv[]){// target = 7, nums = [2,3,1,2,4,3]std::vector<int> test = {2, 3, 1, 2, 4, 3};int target = 7;Solution S1;int res = S1.minSubArrayLen(target, test);std::cout << res << std::endl;return 0;
}
5--循环不变量
主要思路:
定义循环不变量:遵循左闭右开的循环遍历规则;
#include <iostream>
#include <vector>class Solution {
public:std::vector<std::vector<int>> generateMatrix(int n) {std::vector<std::vector<int>> res(n, std::vector<int>(n, 0));int offset = 1, count = 1;int start_x = 0, start_y = 0, i, j;int loop = n / 2;while(loop--){i = start_x;j = start_y;// 上边界左闭右开for(; j < n - offset; j++){res[i][j] = count;count++;}// 右边界上闭下开for(; i < n - offset; i++){res[i][j] = count;count++;}// 下边界右闭左开for(; j > start_y; j--){res[i][j] = count;count++;}// 左边界下闭上开for(; i > start_x; i--){res[i][j] = count;count++;}offset++;start_x++;start_y++;}// 如果n为奇数的话,需要单独给矩阵最中间的位置赋值if (n % 2 == 1) {res[n/2][n/2] = count;}return res;}
};int main(int argc, char argv[]){// n = 4int test = 4;Solution S1;std::vector<std::vector<int>> res = S1.generateMatrix(test);for(auto v : res){for(auto item : v) std::cout << item << " ";std::cout << std::endl;}return 0;
}