基本思路:使用双指针,一个指向数组的头(left),一个指向数组的尾(right),还有一个指针指 ansIndex 向结果数组的末尾(方便进行倒插),对 left 和 right 指向的值的平方进行比较,会有三种情况:
(1)当 left * left < right * right 的时候,将 right * right 放入到结果数组的ansIndex上(这样反着放,出来的结果就是升序,当然也可以不这样,把left放到第一的位置也可以),然后right向左移动一位,left不变,ansIndex向左移动一位。
(2)当 left * left > right * right 的时候,将left * left 的值放入到结果数组的ansIndex上,然后left右移,right不变,ansIndex向左移动一位。
(3)当 left * left == right * right 的时候,随便取两个值中的一个放入到结果数组的ansIndex位置上,然后对应移动(选left就右移,选right就左移),另外一个指针不动,ansIndex向左移动一位。
上述流程写到一个while循环内,循环的终止条件为left >= right(其实只会是等于),当循环结束之后,ansIndex会来到数组的第一个位置(ansIndex == 0),这个时候left 和 right 指向同一个数,随便选择一个,然后再平方放入到ansIndex位置上,最后将结果返回。
Java代码如下:
public int[] sortedSquares(int[] nums) {
int n = nums.length - 1;
int[] ans = new int[n+1];
int left = 0;
int right = n;
while(left < right)
{
if(nums[left] * nums[left] <= nums[right] * nums[right])
{
ans[n--] = nums[right] * nums[right];
right--;
}
else
{
ans[n--] = nums[left] * nums[left];
left++;
}
}
ans[n] = nums[left] * nums[left];
return ans;
}
时间复杂度:O(n)
空间复杂度:O(1)
基本思路:维护一个滑动窗口,需要返回的结果就是滑动窗口的长度(left - right + 1)。滑动窗口就是用两个指针(left,right),left指向滑动窗口的头,right指向滑动窗口的尾,维护一个滑动窗口内的数的和(初始值为0),滑动窗口每次移动的时候就会对和进行加减,刚开始的时候left和right相等。
步骤1:每次循环开始时都将滑动窗口的右边界扩大一位,和也随之扩大。
步骤2:当和大于目标值,将滑动窗口左边界右移一位(滑动窗口缩小),和也减去除去那一位。因为题目需要的是最小的子数组,那么需要维护一个全局的最小子数组长度,minAns(初始值为Integer.MAX_VALUE,这样会在取两者较小值的时候被重新赋值),取minAns和当前滑动窗口的长度的较小值就可以了。这个步骤需要放到一个while循环中,终止条件为 和>=目标值(因为存在减了几次和依然大于目标值的情况)。如果和小于目标值就进入下一轮循环。
上述两个步骤需要放到一个while循环中,终止条件为right >= 数组的长度,当循环结束,返回minAns之前需要判断一下这个值是否为Integer.MAX_VALUE,如果是的话说明没有最小子数组,返回0,反之返回minAns。
Java代码如下:
public int minSubArrayLen(int target, int[] nums) {
int left = 0;
int right = 0;
int sum = 0;
int minAns = Integer.MAX_VALUE;
while(right < nums.length)
{
sum += nums[right++];
while(sum >= target)
{
sum -= nums[left++];
minAns = Math.min(minAns,right - left + 1);
}
}
return minAns == Integer.MAX_VALUE ? 0 : minAns;
}
时间复杂度:O(n)
空间复杂度:O(1)
基本思路:从左到右,从上到下,从右到左,从下到上,为一圈,需要注意圈数,每完成一圈,下一圈矩阵的长宽就会减小2,假设给的长度为4,第一圈结束后,第二圈开始的长宽就变成2了,这一圈结束以后就遍历完毕了,所以圈数就等于4 / 2 = 2圈(相当于4能够减去多少个2,就有多少圈)。用一个start变量表示开始的下标,每转一圈,就加一,因为外圈已经遍历完毕了。变量loop表示现在是第几圈。
(1)从左到右,设 i 为行,j 为列,写一个for循环,j = start(因为每转一圈开始位置会缩小),终止条件为 j < n - loop,j++。n - loop 的含义为当前需要填充的数量,需要 - loop 是因为要把最后一个位置的数留给从上到下的流程处理,保证流程的统一性,每个边的遍历都是左闭右开的形式。循环结束后,i 没有改变,j来到了这一行的最后一位进行下一个流程。
(2)从上到下,现在i,j 所在的位置为矩阵的右上角,执行从上到下的流程,写一个for循环,j 保持不变,i = start ,终止条件为 i > n - loop ,i++ 原理同上。循环结束以后来到了矩阵的右下角,进行下一个流程。
(3)从右到左,现在i,j的位置在矩阵的右下角,写一个for循环,i 保持不变 ,j 现在的值是当前行的最后一位(从左到右的流程给j的值),终止的条件为 j < loop (边界会随着当前的圈数缩小),j--。循环结束之后来到矩阵的左下角,进行下一个流程。
(4)从下到上,现在i,j的位置在矩阵的左下角,写一个for循环,j保持不变,i现在的值为当前矩阵的最后一列,向上遍历,终止条件为 i < loop(原理同上),i--。循环结束之后,当前圈结束。
(5)start++,开始位置向下移动一位。
上述流程写入到一个while循环中,循环的条件为 loop++ < n / 2。++是因为圈数要从1开始,也可以初始化的时候就给1。为什么要除2,原因上面已经讲过了。
当给的n为基数的时候,中心位置会有一个空,需要特殊处理一下,如果是奇数的话,在矩阵的start,start位置单独赋值为count(count是填充的数字,每填充一个就++),为什么是start,start位置呢,因为每一圈start都++,到了最后一圈结束以后,start,start位置就加到了中心位置。
最后将结果返回。
Java代码如下:
public int[][] generateMatrix(int n) {
int i = 0;
int j = 0;
int loop = 0;
int[][] ans = new int[n][n];
int start = 0;
int count = 1;
while (loop++ < n / 2) {
for (j = start; j < n - loop; j++) {
ans[start][j] = count++;
}
for (i = start; i < n - loop; i++) {
ans[i][j] = count++;
}
for (; j >= loop; j--) {
ans[i][j] = count++;
}
for (; i >= loop; i--) {
ans[i][j] = count++;
}
start++;
}
if (n % 2 == 1) {
ans[start][start] = count;
}
return ans;
}
时间复杂度:O(n^2)
空间复杂度:O(1)