977.有序数组的平方
普通方法
唯一想到的就是冒泡排序,但是冒泡排序的时间复杂度已经是O(n^2)
先平方再冒泡
class Solution {
public int[] sortedSquares(int[] nums) {
for (int i = 0; i < nums.length; i++) {
nums[i] = nums[i] * nums[i];
}
for (int i = 0; i < nums.length; i++) {
for (int j = i; j < nums.length; j++) {
if (nums[i] > nums[j]){
int temp = nums[i];
nums[i] = nums[j];
nums[j] = temp;
}
}
}
return nums;
}
}
使用双指针
但是这种情况增加了空间复杂度,感觉是在用空间换时间,空间复杂度变成了O(n),时间复杂度变成了O(n)
- 一个指向头,一个指向尾,因为既然是非递减有序数列,也就意味着平方后的最大值仍然在左或右,所以用两个指针分别指向左和右
- 然后选取左右指针平方大的放到新数组里,而left=right的情况是允许出现的,因为最后一次如果不允许相等,就会漏掉一个元素,而且由于起始位置是左和右两个元素,也就相当于是闭合区间。
- 选取哪一个哪一个指针就进行移动
class Solution {
public int[] sortedSquares(int[] nums) {
int[] result = new int[nums.length];
int left = 0,k = nums.length - 1;
int right = nums.length - 1;
while (left <= right){
int leftVal = nums[left] * nums[left];
int rightVal = nums[right] * nums[right];
if (leftVal > rightVal) {
result[k--] = leftVal;
left++;
} else {
result[k--] = rightVal;
right--;
}
}
return result;
}
}
209.长度最小的子数组
- 如图使用窗口算法进行求解,index作为窗口的左边界,i作为窗口的右边界,那么每次先固定index,移动右边界扩充窗口达到目标窗口范围,并记录此时窗口的长度和大小,
- 之后固定右边界,移动左边界来减小窗口看是否能继续满足条件,如不满足则继续向右边界扩充窗口,依次类推,如此每个元素最多被访问2次,也就相当于2*n的复杂度,即O(n)
- 这样就减少了对整个数组元素的二次访问,并且当左指针不动,右指针找到的窗口一定是当前左指针对应的最小窗口,之后移动左指针相当于重新确定窗口的起点来重新寻找新的窗口,也不会漏掉元素,但是减少了对数组元素的访问
class Solution {
public int minSubArrayLen(int target, int[] nums) {
int index = 0;
int sum = 0;
int len = Integer.MAX_VALUE;
for (int i = 0; i < nums.length; i++) {
sum += nums[i];
while (sum >= target){
len = Math.min(len, i- index + 1);
sum -= nums[index++];
}
}
return len == Integer.MAX_VALUE ? 0 : len;
}
}
59.螺旋矩阵II
- 还是使用左闭右开的方式,就第一圈来说,从左到右选取左闭右开,也就使得第一行被填充,但如上图的2方向,会与之前有重复区域,所以第一行的最后一个元素在填充2方向时才填入,这也是使用一边开一边闭的集合的原因。
class Solution {
public int[][] generateMatrix(int n) {
int[][] result = new int[n][n];
int circle = 1;//记录需要转多少圈
int sum = 1;//每次填入的数字,每次+1
int count = 0;//每转一圈就应该少填充一个格子
int x = 0,y = 0;//初始的横纵坐标,随着圈数变化
int i,j;//i,j为每一圈中的横纵坐标
while (circle++ <= n / 2){
//从左到右,左闭右开,变的是纵坐标,并且右边开区间,所以为n-1
for (j = y; j < n - 1 - count; j++) {
result[x][j] = sum++;
}
//从上到下,上闭下开,变的是横坐标,并且下边开区间,所以为n-1
for (i = x; i < n - 1 - count; i++) {
result[i][j] = sum++;
}
//从右到左,右闭左开,变的是横坐标,并且左边开区间
for (; j > count; j--) {
result[i][j] = sum++;
}
//从下到上,下闭上开,变的是横坐标,并且上边开区间
for (; i > count; i--) {
result[i][j] = sum++;
}
count++;
x++;
y++;
}
if (n % 2 == 1){
result[x][y] = sum;
}//如果为奇数,最后一个数字需要手动填充,因为不会转圈
return result;
}
}