1.有序数组的平方:
思路:首先将数组中的元素值分别平方处理。
开辟一个新数组,变量k指向最大下标处.
设置两个指针,分别为左指针i和右指针j,两指针双向从两端向中间移动,将两指针中大的元素复制给新的数组。更新新数组的下标k,进行k--;
vector<int> result;//开辟 一个新的数组存放最终结果
int k=nums.size-1; 新数组从大到小存放
for(i=0;j=nums.size-1;i<=j){
if(nums[i]*nums[i]>nums[j]*nums[j]){
result[k--]=nums[i]*nums[i];
i++;
}
else{
result[k--]=nums[j]*nums[j];
j--;
}
}
2.长度最小的子数组
1.暴力解法:
两层循环,变量i表长度最小子数组的起点,j表终点。
class Solution{
public:
int minSubArrayLen(int s,vector<int>& nums){
int result=INT32_MAX;//存放最小长度
int sum=0;//子数组总和
int subLength=0;//局部子数组长度
for(int i=0;i<nums.size();i++){ //遍历起点
sum=0;
for(int j=i;j<nums.size();j++){//遍历终点
sum+=nums[j];
if(sum>=s){//局部数组之和大于规定长度
subLength=j-i+1;//局部数组长度
result=result<subLength?result:subLength;//result取最小长度
break;//长度足够,可跳出内层循环
}
}
}
return result==INT32_MAX?0:result;//返回最小长度
}
};
2.滑动窗口(双层遍历的优化版本)
思路:用一个变量j遍历最小子数组的终点位置,确定终点位置之后再移动起点位置i,直到局部长度长度小于规定长度,记录局部数组长度,比较此长度是否为最小。
本质是满足了单调性,即左右指针只会往一个方向走且不会回头。收缩的本质即去掉不再需要的元素。也就是做题我们可以先固定移动右指针,判断条件是否可以收缩左指针算范围。
- 滑动窗口的原理是右边先开始走,然后直到窗口内值的总和大于target,此时就开始缩圈,缩圈是为了找到最小值,只要此时总和还大于target,我就一直缩小,缩小到小于target为止在这过程中不断更新最小的长度值,然后右边继续走,如此反复,直到右边碰到边界。这样就保证了可以考虑到最小的情况
class Solution{
public:
int minSubArrayLen(int s,vector<int>& nums){
int result=INT32_MAX;//存放最小长度
int sum=0;//子数组总和
int i=0;//起点
int subLength=0;//局部数组长度
for(int j=0;j<nums.size();j++){//遍历终点
sum+=nums[j];
while(sum>=s){//局部总和大于规定值,开始缩圈
subLength=(j-i+1);
result=result<subLength?result:subLength;
sum-=nums[i++];
}
}
return result==INT32_MAXX?0:result;
}
};
小知识:双指针其实只有一层遍历,只不过是从头尾开始遍历的。滑动窗口实际上是双层遍历的优化版本。