数组理论基础
常见题
二分法
- 注意区间的选择(左闭右开、左闭右闭)所对应的left、right下标的初始化以及更新。
- 加法加算时,使用
int mid = left + (right - left)/2;
,可以防止数据溢出。
while (left <= right) { // 当left==right,区间[left, right]依然有效,所以用 <=
int middle = left + ((right - left) / 2);// 防止溢出 等同于(left + right)/2
if (nums[middle] > target) {
right = middle - 1; // target 在左区间,所以[left, middle - 1]
} else if (nums[middle] < target) {
left = middle + 1; // target 在右区间,所以[middle + 1, right]
} else { // nums[middle] == target
return middle; // 数组中找到目标值,直接返回下标
}
}
双指针法
-
快慢指针: 通过一个快指针和慢指针在一个for循环下完成两个for循环的工作。
快指针遍历时,用慢指针做记录,不会影响快指针的遍历过程。 -
首尾指针:首尾指针一起遍历,作比较记录结果。
滑动窗口
滑动窗口,就是不断的调节子序列的起始位置和终止位置,从而得出我们要想的结果。
题目 leetcode.cn/problems/mi…
题目 leetcode.cn/problems/fr…
实现滑动窗口,主要确定如下三点:
- 窗口内是什么?
- 如何移动窗口的右边界? 外层for循环
- 如何移动窗口的左边界? 内层while循环
模板
- 最大窗口模板
for (int right = 0; right < nums.length; right ++) {
处理窗口新来元素right;
while (窗口不满足条件) {
处理窗口最左边元素left;
left += 1 // 最保守的压缩i,一旦满足条件了就退出压缩i的过程,使得滑窗尽可能的大
}
更新结果;(注意在while外更新!)
}
- 最小窗口模板
for (int right = 0; right < nums.length; right ++) {
处理窗口新来元素right;
while (窗口满足条件) {
更新结果;(在while内更新!)
处理窗口最左边元素left;
left += 1 // 最大程度的压缩i,满足条件就一直压缩i,使得滑窗尽可能的小
}
}
螺旋矩阵
方法一(模拟法,设定边界,代码简短清晰)
首先是定义上下左右四个边界(l,r,t,b),按照(上右下左)t, r, b, l遍历每条边,每次走完一条边压缩边界并进行判断break;if (++t > b) break;注意是先++,
while (true) {
for (int x = l; x <= r; x++) res[t][x] = count++;
if (++t > b) break;
for (int x = t; x <= b; x++) res[x][r] = count++;
if (--r < l) break;
for (int x = r; x >= l; x--) res[b][x] = count++;
if (--b < t) break;
for (int x = b; x >= t; x--) res[x][l] = count++;
if (++l > r) break;
}
方法二(每圈重新定义边界,比较麻烦,不推荐)
- 每条边左闭右开,按圈循环遍历,总圈数n/2;
- 定义变量;
int startx = 0, starty = 0; // 定义每循环一个圈的起始位置
int loop = n / 2; // 每个圈循环几次,n为奇数时矩阵中间的值需要单独处理
int count = 1; // 用来给矩阵中每一个空格赋值
int offset = 1; // 需要控制每一条边遍历的长度,每次循环右边界收缩一位
int i,j; // 循环赋值时用到的变量res[i][j]