代码随想录算法训练营第二天| 977.有序数组的平方、209.长度最小的子数组、59.螺旋矩阵II

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;
    }
}
  • 6
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值