看到题目,第一眼想到的就是暴力解法,直接先求数组的平方,然后进行排序。
暴力解法代码:
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());
return nums;
}
};
这题用双指针法非常奇妙,我们可以看到题目中给出的数组是有序数组(非单调递减数组),这就说明,我们要返回的数组中最大的数一定在最左边和最右边。所以我们只需要每次比较左右两端元素的平方值,就可以知道最大值。具体操作如下,我们可以创建一个新的数组result,数组大小和我们要处理的数组一样。然后可以创建三个指针,其中一个指针k用来控制新创建的数组result,用来给result赋值,其指向result的最后一个元素,每经过一次比较,result往前走一位,直到给result赋值完毕。另外两个指针用来比较要处理的数组nums,其中一个为左指针left和右指针right,通过比较左右指针所指元素的平方值可以得出最大值,将最大值通过k指针放入result的最后一位,如果左指针所指元素大则将左指针向后移动,右指针所指元素大则将右指针向前移动。具体代码如下:
class Solution {
public:
vector<int> sortedSquares(vector<int>& nums) {
vector<int> result(nums.size());
int k = nums.size()-1;
int left = 0;
int right = nums.size()-1;
while(left<=right)
{
if(nums[left]*nums[left]<nums[right]*nums[right])
{
result[k] =nums[right]*nums[right];
k--;
right--;
}
else
{
result[k]=nums[left]*nums[left];
k--;
left++;
}
}
return result;
}
};
冒泡排序中for循环的含义:
第一个for循环控制要比较次数的次数,第一次比较为N-1次,第二次比较为N-2次,第二个for循环控制比较次数。
for(int i =0;i<N-1;i++)
{
for(int j=0;j<N-1-i;j++)
{
if(nums[j]>nums[j+1];
{
int temp = nums[j];
nums[j] = nums[j+1]
nums[j+1] = temp;
}
}
}
一眼暴力解法。但是暴力解法也有许多需要注意的地方。因为题目要求是寻找长度最小得连续子数组,所以你需要将所有符合条件的子数组穷举出来,然后比较长度,最后输出最小的值。
具体解法如下:首先得定义一个需要输出得结果result,用来保存最后的输出。然后定义一个计算数组长度的值len,用来保存符合条件的数组的长度,还需定义一个sum用来求数组和,用作判断条件。
两层循环:外层循环范围为(0,nums.size()),这个没什么好说的,就是控制数组中的数一个一个后移。内存循环有一点说法,它的范围是(i,nums.size()),而不是(0,nums.size()),可以想想为啥不是从0开始,因为从0开始的话其实一直在重复第一次循环的操作,从而无法找出穷举出所有的子数组。
然后是判断条件,当sum>=target的时候,我们需要记录数组的长度也就是len=j-i+1。然后去不断更新result的长度,我们可以将result定义为最大值,然后去和数组长度比较,如果小于数组长度就令result=len,从而达到不断更新result。最后直接break跳出内层循环。
暴力解法代码如下:
class Solution {
public:
int minSubArrayLen(int target, vector<int>& nums)
{
int len =0;
int result = INT32_MAX;
for(int i = 0;i<nums.size();i++)
{
int sum = 0;
for(int j =i;j<nums.size();j++)
{
sum = sum+nums[j];
if(sum >= target)
{
len = j-i+1;
result = result<len? result:len;
break;
}
}
}
return result==INT32_MAX? 0:result;
}
};
神奇的滑动窗口法:滑动窗口法其实也是双指针法的一种,上面的暴力解法需要两个for循环把所有结果穷举出来,时间复杂度非常大。
其原理为:设置两个指针指向第一个元素,其中一个先往前移动,后一个先不动。后一个在达到判断条件的时候再动。即在sum>=target的时候,这个时候我们还是会和暴力解法做一样的操作,就是记录子数组的长度,然后将他与result比较,与暴力解法不同的是,我们因为前面还预设了一个指针,我们可以通过往前移动指针,然后用sum-nums[i]来移动窗口,这样做就避免了将所有的子数组全部找出来。讲不清楚,画了个图大概就是这么个意思
滑动窗口法代码如下:
class Solution {
public:
int minSubArrayLen(int target, vector<int>& nums)
{
int result = INT32_MAX;
int i = 0;
int sum = 0;
for(int j = 0;j<nums.size();j++)
{
sum = sum+nums[j];
while(sum>=target)
{
int len = j-i+1;
result = result<len? result:len;
sum = sum - nums[i];
i++;
}
}
return result==INT32_MAX? 0:result;
}
};
这题挺难的,对新手非常不友好。
做这题,我们要先明确,n×n数组要转多少圈,我们可以统一是n/2圈不管是奇数还是偶数,区别在于奇数转了n/2圈后会留下一个中心点,中心点的数组下标为(n/2,n/2),如果n为奇数我们可以将其单独赋值为n*n。
所谓转圈,其实就是通过四个方向给数组赋值,可以通过四个循环来实现,但是其需要注意的是,循环的边界问题。为了不使四个循环发生边界冲突,我们可以统一标准都为,左闭右开。
具体的循环操作,我们可以定义两个索引值来作为起点,也就是一个横轴x=0和一个纵轴y=0,由此可见第一圈的循环的的范围为[x,n-1),[y,n-1),[n-1,x),[n-1,y)。每次经过一圈,x++,y++。我们还可以定义一个变量index=1来控制圈数的大小。具体过程如下图:
代码如下:
class Solution {
public:
vector<vector<int>> generateMatrix(int n) {
vector<vector<int>> res(n, vector<int>(n, 0));
int loop = n/2;
int mid = n/2;
int x = 0;
int y = 0;
int index = 1;
int count = 1;
while(loop--)//转圈次数
{
int i = x;
int j = y;
for(j;j<n-index;j++)
{
//赋值
res[x][j]=count++;
}
for(i;i<n-index;i++)
{
res[i][j]=count++;
}
for(j;j>y;j--)
{
res[i][j]=count++;
}
for(i;i>x;i--)
{
res[i][j]=count++;
}
x++;
y++;
index=index+1;
}
if(n%2)
{
res[mid][mid]=n*n;
}
return res;
}
};