代码随想录算法训练营第2天 | 数组2

本文介绍了三种数组操作问题的解决方案:1)使用双指针法对有序数组进行平方并保持非递减排序;2)通过滑动窗口找到和大于等于目标值的最小子数组长度;3)利用循环不变量生成螺旋矩阵。这些方法展示了数组操作的有效策略,如双指针和滑动窗口在优化时间复杂度上的应用。
摘要由CSDN通过智能技术生成

977.有序数组的平方

题目: 给你一个按 非递减顺序 排序的整数数组 nums,返回 每个数字的平方 组成的新数组,要求也按 非递减顺序 排序。
链接: https://leetcode.cn/problems/squares-of-a-sorted-array/
思路:

  1. 暴力解法
    先遍历一边平方,再排序。时间复杂度O(n+nlogn)即O(nlogn)。
  2. 双指针法
    ①定义一个新数组result ,大小与原数组一致,定义一个指针k 指向result数组的终止位置。
    ②定义两个指针i,ji指向原数组最小值,j指向原数组最大值。
    ③新数组排序规则:
    A[i] * A[i] > A[j] * A[j],那么result[k--] = A[i] * A[i],i++
    A[i] * A[i] < A[j] * A[j],那么result[k--] = A[j] * A[j],j--
class Solution {
public:
	vector<int> sortedSquares(vector<int>& nums) {
		vector<int> res(nums.size());
		int lowerPointer = 0;
		int highPointer = nums.size() - 1;
		for(int i = nums.size() - 1; i >= 0; i--){
			if(nums[lowerPointer] * nums[lowerPointer] > nums[highPointer] * nums[highPointer]){
			res[i] = nums[lowerPointer] * nums[lowerPointer];
			lowerPointer++;
			}
			else{
			res[i] = nums[highPointer] * nums[highPointer];
			highPointer--;
			}
		}
		return res;
	}
};

时间复杂度:O(N)
空间复杂度:O(N)

class Solution {
public:
	vector<int> sortedSquares(vector<int>& nums) {
		vector<int> res(nums.size());
		int i = nums.size() - 1;
		for(int lowerPointer = 0, highPointer = nums.size() - 1; lowerPointer <= highPointer;){
			if(nums[lowerPointer] * nums[lowerPointer] > nums[highPointer] * nums[highPointer]){
				res[i] = nums[lowerPointer] * nums[lowerPointer];
				lowerPointer++;
				i--;
			}
			else{
				res[i] = nums[highPointer] * nums[highPointer];
				highPointer--;
				i--;
			}
		}
		return res;
	}
};

209.长度最小的子数组

题目: 给定一个含有 n 个正整数的数组和一个正整数 target 。
找出该数组中满足其和 ≥ target 的长度最小的 连续子数组 [numsl, numsl+1, …, numsr-1, numsr] ,并返回其长度。如果不存在符合条件的子数组,返回 0 。
链接: https://leetcode.cn/problems/minimum-size-subarray-sum
思路: 滑动窗口
①定义一个指针end ,指向滑动窗口的终止位置。
②定义一个指针start,指向滑动窗口的起始位置,当窗口内的子数组满足条件和 ≥ target ,再向后移动start指针,记录在此终止位置end下的最短子数组长度。
③移动终止位置的指针end
注: 所求子数组为连续子数组,当start已经向后移动了,说明此时仍满足和 ≥ target 的条件,而不需要再考虑start之前的元素。

class Solution {
public:
	int minSubArrayLen(int target, vector<int>& nums) {
		int ans = INT32_MAX;
		int sum = 0;
		int start = 0;
		for(int end = 0; end < nums.size(); ++end){
			sum += nums[end];
			while(sum >= target){
				ans = min(ans, end - start + 1);
				sum -= nums[start];
				start++;
			}
		}
		return ans == INT32_MAX? 0 : ans;
	}
};

时间复杂度:O(N)
时间复杂度主要看每一个元素被操作的次数,每个元素作为滑动窗口终止位置被操作一次,滑动窗口起始位置移动时被操作一次,所以时间复杂度是O(2*N)
空间复杂度:O(1)

59.螺旋矩阵II

题目: 给你一个正整数 n ,生成一个包含 1 到 n2 所有元素,且元素按顺时针顺序螺旋排列的 n x n 正方形矩阵 matrix 。
链接: https://leetcode.cn/problems/spiral-matrix-ii/
思路: 循环不变量原则。

  1. 模拟顺时针画矩阵的过程:
    ①填充上行从左到右
    ②填充右列从上到下
    ③填充下行从右到左
    ④填充左列从下到上
  2. 每一行都要坚持左闭右开
    ![[Pasted image 20230112214027.png]]
class Solution {
public:
	vector<vector<int>> generateMatrix(int n) {
		vector<vector<int>> res(n, vector<int>(n, 0));
		int startx = 0;
		int starty = 0;
		int offset = 1;
		int countIndex = 1;
		int i = 0, j = 0;
		int loop = n / 2;
		while(loop--){
			for(j = startx; j < n - offset; ++j){
				res[startx][j] = countIndex++;
			}
			for(i = starty; i < n - offset; ++i)
				res[i][j] = countIndex++;
			}
			for(j = n - offset; j > startx; --j){
				res[i][j] = countIndex++;
			}
			for(i = n - offset; i > starty; --i){
				res[i][j] = countIndex++;
			}
			offset++;
			startx++;
			starty++;
		}
		if(n % 2 == 1){
			res[n / 2][n / 2] = countIndex;
		}
		return res;
	}
};

总结: 遵循循环不变量的规则,一直左闭右开;时刻明确i,j走到哪里了,确定其他相关变量的变化。

总结

数组考察题目常见类型

  1. 二分法
    ①循环不变量:左闭右开 / 左闭右闭;注意每一次二分left/right 的值如何处理。
    ②时间复杂度:O(logn)
  2. 双指针
    通过一个快指针和慢指针在一个for循环下完成两层for循环的工作。通常快指针用于快速遍历完整个数组,慢指针用来更新新的数组元素。
  3. 滑动窗口
    滑动窗口的精妙之处在于根据当前子序列和大小的情况,不断调节子序列的起始位置,将O(N^2)暴力解法的时间复杂度降为O(N)。
  4. 模拟行为
    真正解决题目的代码都是简洁的,或者有原则性的
    注意遵循循环不变量的原则。

数组存储方式

数组存储在连续的内存空间中,且数组中的元素不能删除:

  1. 数组在内存中占用连续的地址空间,不能释放单一元素,如要释放,就要全释放(程序运行结束,回收内存栈空间)。
  2. vector是容器,底层实现是array。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值