Day02 数组
给你一个按 非递减顺序 排序的整数数组 nums,返回 每个数字的平方 组成的新数组,要求也按 非递减顺序 排序。
示例 :
输入:nums = [-4,-1,0,3,10]
输出:[0,1,9,16,100]
解释:平方后,数组变为 [16,1,0,9,100]
排序后,数组变为 [0,1,9,16,100]
这道题的关键在于:
①理解快速排序sort内层机制,快速排序时间复杂度O(nlogn)
②如何实现O(n)时间复杂度的算法,如何巧妙运用双指针实现O(n)的解法
③对于新手来说,掌握动态创建数组
④冒泡排序O(n^2),时间超时
//调用函数sort,快速排序,时间复杂度O(nlogn)
class Solution {
public:
vector<int> sortedSquares(vector<int>& nums) {
for (int i = 0; i < nums.size(); i++) { //每个数平方
nums[i] = nums[i] * nums[i];
}
sort(nums.begin(), nums.end()); //sort排序
return nums;
}
};
//双指针
class Solution {
public:
vector<int> sortedSquares(vector<int>& nums) {
vector<int> result(nums.size(), 0); //创建数组的方式,需掌握!
int k = nums.size()-1;
int left, right; //一个左指针,一个右指针,分别指向数组的左右两侧,因为平方的较大值往往出现在两侧之一(数组是递增)
for (left=0, right=nums.size()-1; left<=right;) { //这里的left--、right--不在for内写,是因为加减是有条件的,所以放在后续If条件内
if(nums[left]*nums[left] > nums[right]*nums[right]) { //左侧平方较大,则将平方后的值填入result数组中
result[k] = nums[left]*nums[left];
k--; //因返回递增数组,所以填入从下标大→小
left++;
} else { //右侧平方较大或者左右相等,则将平方后的值填入result数组中
result[k] = nums[right]*nums[right];
k--;
right--;
}
}
return result;
}
};
给定一个含有 n 个正整数的数组和一个正整数 target 。
找出该数组中满足其和 ≥ target 的长度最小的 连续子数组 [numsl, numsl+1, …, numsr-1, numsr] ,并返回其长度。如果不存在符合条件的子数组,返回 0 。
示例 :
输入:target = 7, nums = [2,3,1,2,4,3]
输出:2
解释:子数组 [4,3] 是该条件下的长度最小的子数组。
这道题的关键在于:
①大于target的数组长度怎么变换更新
②滑动窗口到底是什么?(滑动窗口是不断的调节子序列的起始位置和终止位置,得出想要的结果序列)
③滑动窗口内的双指针怎么规定呢?怎么表示起始位置和结束位置呢?
class Solution {
public:
int minSubArrayLen(int target, vector<int>& nums) {
//因为int占4字节32位,根据二进制编码的规则,INT_MAX = 2^31-1,INT_MIN= -2^31
int sum = 0;
int first = 0;
int len = 0;
int result = INT32_MAX;
for (int last = 0; last < nums.size(); last++) { //这里的循环变量需特别注意,是滑动窗口的关键,循环变量的结束位置
sum += nums[last];
while (sum >= target) {
len = last - first + 1;
result = min(result, len);
sum = sum - nums[first];
first++;
}
}
return result == INT32_MAX ? 0 : result; //若resul在while内有另新赋值,则返回result;否则返回0
}
};
给你一个正整数 n ,生成一个包含 1 到 n2 所有元素,且元素按顺时针顺序螺旋排列的 n x n 正方形矩阵 matrix 。
示例 :
输入:n = 3
输出:[[1,2,3],[8,9,4],[7,6,5]]
这道题的关键在于:
①循环几次
②联想二分法(左开右闭进行遍历)
③每个边界的点怎么处理
④n偶数or奇数的遍历的不同点(奇数n最中间的数需额外填写,偶数n通过遍历即可完成)
class Solution {
public:
vector<vector<int>> generateMatrix(int n) {
vector<vector<int>> nums(n, vector<int>(n, 0)); //使用vector定义二维数组(掌握!)
int startx = 0, starty = 0; //定义x,y起始位置
int offset = 1, count = 1; //offset是控制左闭右开的右开部分,count是需要填写入二维数组的元素
int loop = n / 2; //循环次数,奇数循环一次,偶数循环两次
int i, j;
while (loop--) {
//遍历上下左右特须注意左闭右开,以及边界的考虑
//遍历上行
for (j = starty; j < n - offset ; j++) {
nums[startx][j] = count;
count++;
}
//遍历右行
for (i = startx; i < n - offset; i++) {
nums[i][j] = count;
count++;
}
//遍历下行
for (; j > starty; j--) {
nums[i][j] = count;
count++;
}
//遍历左行
for (; i > startx; i--) {
nums[i][j] = count;
count++;
}
startx++;
starty++;
offset += 1;
}
if (n % 2 == 1) { //如果n为奇数的话,则剩余最中间的点未填写
nums[n/2][n/2] = count;
}
return nums;
}
};
数组的解题思路
二分法关注点:
①循环不变量原则,只有在循环中坚持对区间的定义,才能清楚的把握循环中的各种细节。
②循环不变量:在循环过程中保持不变的性质。
③区间选定:左闭右闭、左闭右开、左开右闭、左开右开(掌握前两个即可),选定完区间,循环条件就要多加注意
时间复杂度O(logn)
双指针法(快慢指针法):通过一个快指针和慢指针在一个for循环下完成两个for循环的工作。
时间复杂度O(n)
理解滑动窗口
①如何移动窗口起始位置,达到更新符合题目要求的子序列窗口大小,从而得出长度最小的符合条件的长度。
②精妙之处:根据当前子序列和大小的情况,不断调节子序列的起始位置
时间复杂度O(n)
循环不变量原则
区间选择
边界处理
每日一更实属不容易,加油!
欢迎大家指正!感谢!