LeetCode.977 有序数组的平方
这道题可以使用暴力解法来解决,先将数组中所有的元素都平方后,再排序。但是这样的话时间复杂度太高了。所以我们使用双指针的思路来解决这道题。
前言说过,我们如果使用双指针这种思路,应该要确定双指针到底是干什么的。
这里我们定义两个指针,一个指针叫 left ,一个指针叫 right。
left :指向数组的第一个元素
right:指向数组的最后一个元素
确定了两个指针,我们使两个指针一个从前,一个从后,逐渐的靠近,直到等于为止。这样就遍历了数组中所有的元素。然后我们在遍历中找出平方后最大的元素将其加入到新数组的最后面,这样我们在输出新数组的时候,就完成了数组的从小到大的遍历。
代码如下:
public int[] sortedSquares(int[] nums) {
//定义两个指针,一个指向数组的第一个元素,一个指向数组的最后一个元素
int right = nums.length - 1;
int left = 0;
//定义返回结果的新数组
int[] result = new int[nums.length];
//这时新数组的最后一个下标,我们找到平方后的最大元素
//然后将最大的元素加到新数组的最后一个下标下,这样
//我们在输出的时候就完成数组的从小到大的排序。
int index = result.length - 1;
//这里解释为什么是 left <= right,其实这和我们定义的区间有很大关系
//我们定义的区间是 数组的第一个元素和数组的最后一个元素,这里我们如果
//写的是 left < right ,那么我们是不是就少遍历了一个元素呢????
while (left <= right) {
//这一步就是我们找出平方后的最大元素
//找到了,我们就加入到新数组的最后位置
if (nums[left] * nums[left] > nums[right] * nums[right]) {
// 正数的相对位置是不变的, 需要调整的是负数平方后的相对位置
result[index--] = nums[left] * nums[left];
++left;
} else {
result[index--] = nums[right] * nums[right];
--right;
}
}
return result;
}
LeetCode.209长度最小的子数组
本题需要利用滑动窗口的理论。
实现滑动窗口,主要确定三点:
- 窗口内是什么?
- 如何移动窗口的起始位置?
- 如何移动窗口的结束位置?
窗口就是满足 其和 >= s 的长度的数组。
窗口的起始位置如何移动:如果当前窗口的值大于s了,窗口就要向前移动了,即需要缩小。
窗口的结束位置如何移动:窗口的结束位置就是遍历数组的指针。
解题的关键在于 窗口的起始位置如何移动,如图所示:
代码如下:
public int minSubArrayLen(int target, int[] nums) {
//定义一个初始值
int result = Integer.MAX_VALUE;
int sum = 0;
//定义数组的长度
int subLen = 0;
int j = 0;
for (int i = 0; i < nums.length; i++) {
//定义sum用于收集nums[i]的和
sum += nums[i];
while (sum >= target) {
//每次更新subLen的值去做比较
subLen = i - j + 1;
result = Math.min(result, subLen);
//j向前移动一位,将sum的和减去num[j]
sum -= nums[j++];
//也可以这样写 sum = sum - nums[j];j++;
}
}
//加了一个判断,如果result还是Integer的最大值,说明没有找到,返回0
return result == Integer.MAX_VALUE ? 0 : result;
}
LeetCode.59螺旋矩阵II
本题并没有涉及到算法,只要是考察我们对循环不变量的原则。
模拟顺时针画矩阵的过程:
- 填充上行从左到右
- 填充左侧从上到下
- 填充下行从右到左
- 填充右侧从下到上
由外到内一圈一圈的去填充,我们一定要按照固定的规则去填充,填充每条边都要坚持一直的左闭右闭,或者左闭右开。
代码如下(左闭右开):
public int[][] generateMatrix(int n) {
int loop = 0;//控制循环的次数
int[][] result = new int[n][n];//返回结果的数组
int start = 0;//每次循环的开始点
int count = 1;//定义填充的数字
int i, j;
while (loop++ < n / 2) {//判断边界后,loop从1开始
//模拟上侧从左到右
for (j = start; j < n - loop; j++) {
result[start][j] = count++;
}
//模拟左侧从上到下
for (i = start; i < n - loop; i++) {
result[i][j] = count++;
}
//模拟上侧从右到左
for (; j >= loop; j--) {
result[i][j] = count++;
}
//模拟右侧从下到上
for (; i >= loop; i--) {
result[i][j] = count++;
}
//注意别忘记了start++
//这里为什么要++呢?
//因为我们已经遍历完一圈了,我们将外层的一圈遍历结束
//下一步我们要去遍历内层。即 i =1,j =1 的那圈。
start++;
}
//处理是n是奇数的情况
if (n % 2 == 1) {
result[start][start] = count;
}
return result;
}