数组刷题总结

71 阅读3分钟

数组

1. 二分查找法/二分搜索法

[left, right] (左闭右闭版本,也就是左可以等于右版本) :根据区间来写right 和 left的取值也就是+1或者-1,如果while里面写的是<=也就是有等号,说明后面的取值要符合定义,也就是取值合法。如[1,1] (包含1,又包含1,所以是一个合法的区间);写right = middle是不合法的,因为middle不是我们要寻找的值,而应该写right = middle -1

// [left, right]是合法区间
left = 0;
right = numSize - 1;
while(left <= right)
{
middle = (left + right)/2;
if(nums[middle] > target){
right = middle - 1;
}
else if(nums[middle] < target){
left = middle + 1;
}
else return middle;
}
return -1;

[left, right) (左闭右开版本) :举例子[1,1)既包含1,又不包含1,是一个不安全的,所以循环条件♻️是left < right。因为是右开,所以更新right的时候是right = middle

// [left, right)是合法区间
left = 0;
right = numSize;//小心
while(left < right)
{
middle = (left + right)/2;
if(nums[middle] > target){
right = middle;
}
else if(nums[middle] < target){
left = middle + 1;
}
else return middle;
}
return -1;

leetcode.cn/problems/bi…

class Solution {
public:
   int search(vector<int>& nums, int target) {
     //[left,right]
   int left = 0;
   int right = nums.size() - 1;
   while(left <= right)
  {
       int middle = (left + right)/2;
       if(nums[middle] > target)
           right = middle - 1;
       
       else if(nums[middle] < target)
           left = middle + 1;
       
       else return middle;
  }
   return -1;
  }
};
class Solution {
public:
   int search(vector<int>& nums, int target) {
   // [left, right)
   int left = 0;
   int right = nums.size(); //这一步要小心,定义的时候
   while(left < right){
       int middle = left + (right - left)/2;
       if(nums[middle] < target) left = middle + 1;
       else if(nums[middle] > target) right = middle;
       else return middle;
  }
   return -1;
  }
};

2. 移除元素

使用双指针

class Solution {
public:
   int removeElement(vector<int>& nums, int val) {
       int fast = 0 , slow = 0;
       for(fast = 0; fast < nums.size(); fast++)
      {
           if(nums[fast]!= val){
               nums[slow] = nums[fast];
               slow++;
          }
      }
       return slow;
  }
};

3. 删除有序数组中的重复项

用到的是快慢指针,和移除元素一个思想

class Solution {
public:
   int removeDuplicates(vector<int>& nums) {
       int fast = 0, slow = 0;
       for(fast = 0; fast< nums.size(); fast++){
           if(nums[fast] != nums[slow])
          {
               slow++;
               nums[slow] = nums[fast];
          }
      }
       return slow + 1;
  }
};

4. 有序数组的平方

从前和从后往里面缩,将初始化的vector从后往前赋值(从前往后是从小到达,那么从后往前就是从大到小)

class Solution {
public:
   vector<int> sortedSquares(vector<int>& nums) {
       int newSize = nums.size() - 1;//尾指针的下标
       vector<int> newNums(nums.size(),0);
       
       for(int i = 0 , j = nums.size() - 1; i <= j ;)
      {
           if(nums[i] * nums[i] < nums[j] * nums[j]){
               newNums[newSize] = nums[j] * nums[j];
               --j;
          }
           else{
               newNums[newSize] = nums[i] * nums[i];
               ++i;
          }
           newSize--;
      }
       return newNums;
  }
};

5. 长度最小的子数组

需要一个头指针,一个尾指针,尾指针先走,头指针不断靠近尾指针,只要满足两个指针中间包括两个指针指的元素之和大于等于target,头指针一个一个往后挪,记得sum要减去每一个头指针指向的数值,遍历完后返回target

class Solution {
public:
   int minSubArrayLen(int target, vector<int>& nums) {
       int j = 0, i = 0;
       int ret = INT32_MAX;//结果值
       int sum = 0; //用来临时保存滑动内的总和
       for(j = 0; j < nums.size(); ++j)
      {
           sum += nums[j];
           while(sum >= target){                
               ret = min(j - i + 1, ret);
               sum -= nums[i];
               ++i;
          }
      }
       if(ret == INT32_MAX)return 0;
       return ret;
  }
};

6. 螺旋矩阵 II

因为是顺时针旋转赋值,我们需要计算旋转轮数,轮数loop是n/2,一圈遍历四次,每次一条边少一个元素留给下一条边遍历(也就是说的左闭右边开),遍历完一圈记得设置开始遍历位置(startx, starty),以及offset要加一(因为offset是用来计算右开的位置); 最后如果是奇数,还要补最中间的格子

注:不要忘了starts,starty在循环开始地方的更新

class Solution {
public:
    vector<vector<int>> generateMatrix(int n) {
        vector<vector<int>> res(n, vector<int>(n,0));//vector定义二维数组
        int loop = n/2;
        int startx = 0 , starty = 0;
        int offset = 1;
        int i = 0, j = 0;
        int count = 1; //count是从1开始慢慢+1的
        while(loop--)
        {
            //第一步一定不要缺,更新startx,starty
            i = startx;
            j = starty;

            for(j = starty; j < n - offset; ++j)res[i][j] = count++; // 因为坐标(i,j),这边j在变化, 遍历左到右
            for(i = startx; i < n - offset; ++i) res[i][j] = count++;//遍历右上到右下
            for(; j > starty; --j) res[i][j] = count++;//遍历右下到左下
            for(; i > startx; --i) res[i][j] = count++;//遍历左下到左上

            startx++;
            starty++;//初始点的更新,更新到右下的格子
            offset++;
        }
        if(n%2)res[n/2][n/2] = count;
        return res;
    }
};