1 有序数组的平方
1.1 暴力解法
直接将数组内的所有数平方,之后利用sort函数对数组进行快排
class Solution {
public:
vector<int> sortedSquares(vector<int>& nums) {
int size = nums.size();
for(int i = 0; i < size; i++){
nums[i] *= nums[i];
}
sort(nums.begin(),nums.end());
return nums;
}
};
时间复杂度:O (n+nlogn)
for循环时间复杂度O (n)
快排时间复杂度O (nlogn)
1.2 双指针
数组本身是升序,但是有负有正,所以平方后的最大值就在两端,从这点出发,利用双指针相向而行,进行判断,然后放入新数组。
class Solution {
public:
vector<int> sortedSquares(vector<int>& nums) {
int size = nums.size();
int left = 0;
int right = size-1;
vector<int> result(size,0);
while(left <= right){
if(abs(nums[left]) > abs(nums[right])){
result[size-1] = nums[left]*nums[left];
left++;
size--;//新数组要从后往前进行填充,所以size--
}else{
result[size-1] = nums[right]*nums[right];
right--;
size--;
}
}
return result;
}
};
时间复杂度:O(logn)
2 长度最小的子数组
2.1 暴力解法
利用双层for循环,外层寻找目标子数组起始点,内层寻找终止点:将起始点到终止点进行加和,满足条件就更新目标result;起始点变化时,sum重置,重新开始寻找终止点。
利用INT_MAX来帮助更新result,不断取最小值,最终找到目标子数组长度
常量INT_MAX和INT_MIN分别表示最大、最小整数,定义在 头文件limits.h中。
INT_MAX = 2^31-1,INT_MIN= -2^31
class Solution {
public:
int minSubArrayLen(int target, vector<int>& nums) {
int result = INT_MAX;//定义一个最大值,便于后面不断更新结果
int length = 0;
int size = nums.size();
for(int i = 0; i < size; i++){ //目标子数组起始点
int sum = 0;
for(int j = i; j < size; j++){//目标子数组终止点
sum += nums[j]; //求和
if(sum >= target){ //满足条件
length = j-i+1;//更新此时数组的长度
result = min(result,length);//更新结果集:取result和length最小值
break;//得到结果直接跳出循环
}
}
}
return result == INT_MAX ? 0 : result;//如果result依然是初始化值说明数组之中没有满足条件的子数组
}
};
时间复杂度:O (n²)
超时
2.2 滑动窗口
实质上就还是双指针法:一个指针寻找终点,一个指针找起始点
//滑动窗口:即双指针,一个指针找终点,一个指针找起点
class Solution {
public:
int minSubArrayLen(int target, vector<int>& nums) {
int result = INT_MAX;//定义一个最大值,便于后面不断更新结果
int length = 0;
int sum = 0;
int size = nums.size();
int start = 0;//起始指针
for(int end = 0; end < size; end++){ //目标子数组终点:
//如果这里是起点,那么终点就要从头开始遍历,这样和暴力解法并无区别
sum += nums[end];
while(sum >= target){ //用while的原因:后面可能还有满足条件的数组,用if就会忽略后面的元素
length = end-start+1;
result = min(length,result);
sum -= nums[start++];
}
}
return result == INT_MAX ? 0 : result;//如果result依然是初始化值说明数组之中没有满足条件的子数组
}
};
关于for循环里面是起始点还是终止点:
如果是起点,也就是说终点要从头开始遍历,此时和暴力法并无区别
时间复杂度:O(n)
时间复杂度主要是看每一个元素被操作的次数,每个元素在滑动窗后进来操作一次,出去操作一次,每个元素都是被操作两次,所以时间复杂度是 2 × n 也就是O(n)
3 螺旋矩阵Ⅱ
本题主要是模拟过程,关键是循环不变量:要左闭右开,就都左闭右开;要左闭右闭就都左闭右闭
模拟顺时针画矩阵的过程:
填充上行从左到右
填充右列从上到下
填充下行从右到左
填充左列从下到上
本题中如果n为奇数时,旋转的圈数是n/2+1,最后一圈需要单独处理,也就是正方形中心处,只有一个元素,找到中心的位置坐标nums[n/2][n/2],直接令其等于n的平方。
当n为偶数时,旋转圈数为n/2,就顺时针一圈一圈进行元素填充
class Solution {
public:
vector<vector<int>> generateMatrix(int n) {
vector<vector<int>> vec(n,vector<int>(n,0));
int startX = 0;//每一圈的开始坐标都是变化的,所以设置X和Y
int startY = 0;
int offSet = 1;//遵循左闭右开原则,每次填充元素要减去offset
int loop = n/2;//设置循环次数,当n为奇数时,单独进行处理
int mid = n/2;//设置正方形中心元素,当n为奇数时,单独进行处理
int count = 1;//设置填充元素
int i,j;
while(loop--){
i = startX, j = startY;
//上:从左到右进行填充
for(j = startY; j < n - offSet; j++ ){
vec[i][j] = count++;
}
//右:从上到下
for(i = startX; i < n - offSet; i++){
vec[i][j] = count++;
}
//下:从右到左
for(; j > startY; j--){ //j此时已经到了n-offset处,不需要再进行初始化
vec[i][j] = count++;
}
//左:从下到上
for(; i > startX; i--){
vec[i][j] = count++;
}
//进行第二圈填充的准备
startX++;//起始位置变化
startY++;
offSet++;
}
//处理n为奇数
if(n%2 == 1){
vec[mid][mid] = count;
}
return vec;
}
};