数组是存放在连续内存空间上的相同类型数据的集合。
3.1.1移除元素-暴力解法
双层 for 循环,内层for循环遍历外层for循环剩余未遍历数组元素。
// 空间复杂度:O(1)
class Solution {
public:
int removeElement(vector<int>& nums, int val) {
int size = nums.size();
for (int i = 0; i < size; i++) {
if (nums[i] == val) { // 发现需要移除的元素,就将数组集体向前移动一位
for (int j = i + 1; j < size; j++) {
nums[j - 1] = nums[j];
}
i--; // 因为下标i以后的数值都向前移动了一位,所以i也向前移动一位
size--; // 此时数组的大小-1
}
}
return size;
}
};
3.1.2移除元素-快慢指针法:
快指针for循环遍历数组。对于非目标值,快指针将该元素赋值于慢指针数组位置处,然后慢指针自加1;
如果快指针指向元素是目标值,快指针自加,慢指针不动。最后返回慢指针。
// 时间复杂度:O(n)
// 空间复杂度:O(1)
class Solution {
public:
int removeElement(vector<int>& nums, int val) {
int slowIndex = 0;
for (int fastIndex = 0; fastIndex < nums.size(); fastIndex++) {
if (val != nums[fastIndex]) {
nums[slowIndex++] = nums[fastIndex];
}
}
return slowIndex;
}
};
3.1.3移除元素-双向指针
左侧负责寻找val位置,右侧负责寻找不为val的位置,找到后将右侧的值覆盖到左侧。
循环中需要写成 left <= right,当left-right区间内没有val时,left需要自增到right位置
class Solution {
public:
int removeElement(vector<int>& nums, int val) {
int leftindex = 0;
int rightindex = nums.size()-1;
while(leftindex <= rightindex){
//左侧寻找val
while(leftindex <= rightindex && nums[leftindex] != val){
leftindex++;
}
//右侧寻找不为val
while(leftindex <= rightindex && nums[rightindex] == val){
rightindex--;
}
if(leftindex<rightindex){
nums[leftindex++] = nums[rightindex--];
}
}
return leftindex;
}
};
3.2.1有序数组的平方-暴力解法
先遍历,计算平方,然后排序
class Solution {
public:
vector<int> sortedSquares(vector<int>& nums) {
for(int i = 0;i<nums.size();i++){
nums[i] *= nums[i];
}
sort(nums.begin(),nums.end());//这里直接调用了排序算法
return nums;
}
};
3.2.2有序数组的平方-双指针法
两两比较,最后会剩下两个元素,这两个元素都需要加到新数组中,所以需要添加等号。
class Solution {
public:
vector<int> sortedSquares(vector<int>& A) {
int k = A.size()-1;
vector<int> result(A.size(),0);
int j = A.size()-1;
for(int i = 0;i<=j;){
if(A[i]*A[i]<A[j]*A[j]){
result[k--] = A[j]*A[j];
j--;
}
else{
result[k--] = A[i]*A[i];
i++;
}
}
return result;
}
};
3.3.1长度最小的子数组-暴力解法
两个循环遍历数组,外层循环 i 从0到nums.size,内层循环由 i 到nums.size()
class Solution {
public:
int minSubArrayLen(int target, vector<int>& nums) {
int result = INT32_MAX;
int sum = 0;
int sublength = 0;
for(int i=0;i<nums.size();i++){
sum = 0;//每次计算时需要将sum清零
for(int j=i;j<nums.size();j++){//计算i及后面元素和
sum+=nums[j];
if(sum >= target){
sublength = j - i + 1;//计算数组元素连续长度
result = result < sublength ? result : sublength;//判断是否需要更新
break; //找到符合要求的就不需要往下找了
}
}
}
return result == INT32_MAX? 0:result;
}
};
3.3.2长度最小的子数组-滑动窗口法
类似于双指针,右侧指针用于遍历,将新遍历得到的数组元素放进sum中,左侧指针根据条件选择性右移。
while循环不断判断两个指针间的元素和是否大于等于target,若超出需要将左指针往右移,并且将sum更新。
while中加入等于判断是因为题目中要求找 >= target 的子数组。
class Solution {
public:
int minSubArrayLen(int target, vector<int>& nums) {
int result = INT32_MAX;
int sum = 0;
int sublength = 0;
int i = 0;
for(int j=0;j<nums.size();j++){
sum += nums[j];
while(sum>=target){
sublength = j-i+1;
result = sublength<result ? sublength:result;
sum -=nums[i++];
}
}
return result == INT32_MAX? 0:result;
}
};
3.4螺旋矩阵
首先遵循顺时针从左到右,从上到下的顺序,一圈一圈更新矩阵数据。
更新过程中遵循左闭右开,即对于拐角处数据,每次处理左侧,右侧留给下一组。
循环写入后,还需要判断一下n是否为奇数,如果是奇数,需要单独填充最中间的值。
class Solution {
public:
vector<vector<int>> generateMatrix(int n) {
vector<vector<int>> res(n,vector<int>(n,0));
int middle = n/2;
int offset = 1;//统一按照左闭右开的方式逐圈更新
int startx = 0,starty = 0;
int loop = n/2;
int count = 1;
while(loop--){
int i = startx;
int j = starty;
for(j = starty;j < n-offset;j++){//上行从左到右,左闭右开
res[startx][j] = count;
count++;
}
for(i = startx;i < n-offset;i++){//右列从上到下,左闭右开
res[i][j] = count;
count++;
}
for(;j>starty;j--){//下行从右到左,左闭右开
res[i][j] = count;
count++;
}
for(;i>startx;i--){//左列从下到上,左闭右开
res[i][starty] = count;
count++;
}
startx++;//写完一圈更新初始值
starty++;
offset++;//左闭右开偏移值也需要更新
}
if(n%2){
res[n/2][n/2] = n*n;
}
return res;
}
};