断断续续刷了不少的leetcode题目了,但是算法一点长进都没有,还是一个小白(简单题重拳出击,中等题唯唯诺诺,困难题看不懂);究其根本原因,就是自己没有好好认真的学习,既缺乏系统性的学习,也没有做记录,刷过了就忘了,同类题型不会做。现将自己刷题学习的过程记录下来,留做以后翻阅,内容比较混乱,自用。
二分查找
二分查找的题目中,看到有序性,可以考虑二分查找
复杂度为 O(logn)
主要是理解边界问题,记录两种常见情况
左闭 left+1,右闭 right-1
[left,right] 判断条件 <=
[left,right) 判断条件 <
相关题目
题目 | 难度 |
---|---|
278. 第一个错误的版本 | 简单 |
374. 猜数字大小 | 简单 |
34. 在排序数组中查找元素的第一个和最后一个位置 | 中等 |
658. 找到 K 个最接近的元素 | 中等 |
求最大公因数(辗转相除法)
求数字a和b的最大公因数
写法一:循环
public int gcd (int a, int b) {
while(b > 0){
int c= a % b;
a = b;
b = c;
}
return a;
}
写法二:递归
public int gcd(int a, int b){
if(b == 0) return a;
return gcd(b,a % b);
}
双指针和滑动窗口
通常我们把窗口大小不固定的叫双指针,固定的叫滑动窗口,使用双指针的要求是单调性
同向双指针
题目
长度最小的子数组
这道题第一反应是两层循环,暴力枚举求和,取最小的满足值,复杂度为O(n2),
但是其实在循环中,有很多的求和是不必要的,比如说已经找到一个长度为x的连续子数组满足,其实就没有必要在算那些大于x的连续子数组了,想象一个在缩小的滑动窗口,复杂度为O(n)
以target = 7, nums = [2,3,1,2,4,3] 为例
遍历右端点
l = 0 r = 0 [2] sum = 2 <7
l = 0 r = 1 [2,3] sum = 5<7
l = 0 r = 2 [2,3,1] sum = 6<7
l = 0 r = 3 [2,3,1,2] sum = 8>7 满足 记录下ans = 4 此时窗口的大小就是4,不用考虑>4的了,此时收缩左边的端点,看是否仍然可以符合
l = 1 r = 3 [3,1,2] sum = 6<7 不满足,恢复长度为4的窗口,往右移动一下,
l = 1 r = 4 [3,1,2,4] sum = 10>7 满足 ans = 4 继续收缩
l = 2 r = 4 [1,2,4] sum = 7=7 满足 ans = 3 继续收缩
l = 3 r = 4 [2,4] sum=6<7 不满足,恢复长度为3的窗口,往右移动一下,
l = 3 r = 5 [2,4,3] sum = 9 >7 满足 ans = 3 继续收缩
l = 4 r = 5 [4,3] sum = 7=7 满足 ans = 2 继续收缩
l = 5 r = 5 [3] sum = 3<7
所以最后的结果就是 ans = 2
class Solution {
public int minSubArrayLen(int target, int[] nums) {
int ans = Integer.MAX_VALUE;
int sum = 0;
int left = 0;
for(int right=0;right<nums.length;right++){
sum += nums[right];
while(sum>=target){
ans = Math.min(ans,right-left+1);
sum -= nums[left];
left++;
}
}
return ans==Integer.MAX_VALUE?0:ans;
}
}
其他题目
埃氏筛
//求10e6内的质数
static int n = 1000000;
static HashSet<Integer> set = new HashSet<>();
static{
boolean[] is_prime = new boolean[n+1];
for(int i=2;i<=n;i++){
if(!is_prime[i]){
set.add(i);
}
for(int j=i;j<=n/i;j++){ //防止溢出
is_prime[i*j] = true; //不是质数
}
}
}