力扣刷题总结 数组(1)

 🔥博客主页: A_SHOWY
🎥系列专栏力扣刷题总结录 数据结构  云计算

跟随代码随想录初刷力扣算法,语言全部用c++,记录总结

704. 二分查找easy二分法
35.  搜索插入位置easy二分法

34. 在排序数组中查找元素的第一个位置和最后一个位置

mid二分法
69. X的平方根easy二分法
367. 有效的完全平方数easy二分法
27. 移除元素easy双指针
26. 删除有序数组中的重复项easy双指针
283. 移动0easy双指针
844. 比较含退格的字符串easy双指针
977. 有序数组的平方和easy双指针
209. 长度最小的子数组mid滑动窗口        
904. 水果成篮mid滑动窗口
59. 螺旋矩阵2mid螺旋矩阵
54. 螺旋矩阵mid螺旋矩阵

一、数组基础理论

1.数组是存放在连续空间的相同类型数据的集合

  • 数组下标都是从0开始的。

  • 数组内存空间的地址是连续的

2.要注意vector 和 array的区别,vector的底层实现是array,严格来讲vector是容器,不是数组

3.数组的元素是不能删的,只能覆盖。 在C++中二维数组是连续分布的

二、二分查找

(1)704. 二分查找

704. 二分查找icon-default.png?t=N7T8https://leetcode.cn/problems/binary-search/

class Solution {
public:
    int search(vector<int>& nums, int target) {
     int left = 0;
     int right = nums.size() - 1;//这里定义target在一个左闭右开区间
    while (left <= right)//所以这里等于的时候有意义
    {
        int mid = left + ((right - left)/2);//注意这里防止溢出
        if(target < nums[mid])
        {
            right = mid - 1;
        }
        else if( nums[mid] < target)
        {
            left = mid + 1;
        }
       else {return mid;}
    }  
     return -1;
    }
}

        为了方便记忆,可以一律统一使用左闭右闭经典二分法

(2)35.  搜索插入位置

35. 搜索插入位置icon-default.png?t=N7T8https://leetcode.cn/problems/search-insert-position/

//其实可以直接套用二分法,然后在小的地方插入,target小于mdiddle时,借助ans
class Solution {
public:
    int searchInsert(vector<int>& nums, int target) {
     int left = 0;
     int right = nums.size() -1;
     int ans = nums.size();
     while (left<= right)
     {
         int middle = ((left+right)/2);
      
         if(nums[middle]>=target)
         {
             ans = middle;
             right = middle-1;
         }
            else
         {
             left = middle+1;
         }
        
     }
      return ans;
    }
};

        经典的二分法问题,多考虑一下当nums[mid] >= target 的时候,让ans(基准)移动到mid。

(3)34. 在排序数组中查找元素的第一个位置和最后一个位置

34. 在排序数组中查找元素的第一个和最后一个位置icon-default.png?t=N7T8https://leetcode.cn/problems/find-first-and-last-position-of-element-in-sorted-array/

class Solution {
public:
    vector<int> searchRange(vector<int>& nums, int target) {
     int lborder = getLborder(nums,target);
     int rborder = getRborder(nums,target);
     //情况1
     if(lborder == -2 || rborder == -2) return{-1,-1};
     if((rborder -lborder) >1) return{lborder+1,rborder-1};
     return{-1,-1};
    }
    int getLborder(vector<int>& nums,int target)
    {
        int left = 0;
        int right = nums.size() - 1;
        int lborder = -2;
        while(left <= right)
        {
            int mid = (left +(right-left)/2);
            if(nums[mid] < target)
            {
                left = mid + 1;
                
            }
            else{right = mid -1;
            lborder = right;
            }
        }
        return lborder;
    }
    int getRborder(vector<int>& nums,int target)
    {
        int left = 0;
        int right = nums.size() - 1;
        int rborder = -2;
        while(left <= right)
        {
            int mid = (left +(right-left)/2);
            if(nums[mid] > target)
            {
                right = mid -1;
               
            }
            else
            {
               left = mid + 1;
                rborder = left;
            }
        }
        return rborder;
    }
};

思路:要用到两个二分法寻找左右边界,核心在于更新边界在等于的时候 

要考虑到三种情况:

1、target在左边或者右边

2、target在之中但是不存在

3、target在其中并且存在。

为了寻找这三种情况,需要用两次二分法寻找左右边界。

(4)69. X的平方根

69. x 的平方根 icon-default.png?t=N7T8https://leetcode.cn/problems/sqrtx/

class Solution {
public:
    int mySqrt(int x) {
        int left = 0;
        int right = x;
       int  ans = -2;
        while(left<=right)
        {
            int mid = left+((right-left)/2);
            if((long)mid * mid >= x)
            {
                left = mid + 1;
                ans = left;
            }
            else {right = mid-1;}
        }
return ans;
    }
};

二分法,把平方根在0到x进行二分使其满足平方<x

(5)367. 有效的完全平方数

367. 有效的完全平方数icon-default.png?t=N7T8https://leetcode.cn/problems/valid-perfect-square/

class Solution {
public:
    bool isPerfectSquare(int num) {
   int left = 0;
   int right = num;
   int ans = -2;
   while (left <= right)
   {
       int mid = (left+(right-left)/2);
       long square = (long)mid*mid;
       if(square < num)
       {
           left = mid + 1;
       }
       else if (square > num)
       {
           right = mid -1;
       }
       else return true;
   }
   return false;
    }
};

        二分法,看到平方可以考虑二分法

三、移除元素

使用erase库函数时,时间复杂度是o(n)双指针法

双指针法(快慢指针法): 通过一个快指针和慢指针在一个for循环下完成两个for循环的工作。

定义快慢指针

  • 快指针:寻找新数组的元素 ,新数组就是不含有目标元素的数组

  • 慢指针:指向更新 新数组下标的位置

(1)27. 移除元素

27. 移除元素icon-default.png?t=N7T8https://leetcode.cn/problems/remove-element/

class Solution {
public:
    int removeElement(vector<int>& nums, int val) {


int sn = 0;
for(int fn = 0;fn<nums.size();fn++)
{
    if(nums[fn]!= val) 
    {
        nums[sn] = nums[fn];
         sn++;

    }
}
return sn;
    }
};

        思路:让快指针走,遇到不要的元素就跳过,遇到要的就给慢指针

(2)26. 删除有序数组中的重复项

26. 删除有序数组中的重复项icon-default.png?t=N7T8https://leetcode.cn/problems/remove-duplicates-from-sorted-array/

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

    思路同上题基本一模一样,练习 

(3)283. 移动0

283. 移动零icon-default.png?t=N7T8https://leetcode.cn/problems/move-zeroes/

class Solution {
public:
    void moveZeroes(vector<int>& nums) {
    int slow = 0;
    for(int fast = 0;fast < nums.size();fast++)
    {
        if(nums[fast] != 0)
        {
            nums[slow] = nums[fast];
            slow++;
        }
    }
    for(int k =slow ;k< nums.size();k++)
    {
        nums[slow] = 0;
        slow++;
    }
    }
};

    思路:双指针把0去掉,再循环加0 。和27的思路一致

    

(4)844. 比较含退格的字符串

844. 比较含退格的字符串icon-default.png?t=N7T8https://leetcode.cn/problems/backspace-string-compare/

class Solution {
public:
    bool backspaceCompare(string s, string t) {
    int t1 = 0;
    int t2 = 0;
    int i = s.length() - 1;
    int j  = t.length() - 1;
//先把所有的#相关的去掉    
while(1)
    {
        while(i >= 0)
        {
            if( s[i] == '#')
            {
                t1++;
            }
            else
            {
                if(t1 > 0) t1--;
                else break;
            }
            i--;
        }
         while(j >= 0)
        {
            if( t[j] == '#')
            {
                t2++;
            }
            else
            {
                if(t2 > 0) t2--;
                else break;
            }
            j--;
        }
        if(i<0 || j<0) break;
        if(s[i] != t[j]) return false;
        i--;j--;
        
    }
        if(i==-1 && j==-1) return true;
        return false;
    }
};

核心思路:核心是先把#的前面的字符去掉,然后再使用双指针逐个比较

(5)977. 有序数组的平方和

977. 有序数组的平方icon-default.png?t=N7T8https://leetcode.cn/problems/squares-of-a-sorted-array/

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;
    }
   
};

2.双指针方法

class Solution {
public:
    vector<int> sortedSquares(vector<int>& nums) {
        int n = nums.size();
         vector<int> ans(n); 
         for(int i = 0,j = n-1, p= n-1; i<=j;)
         {
             if(nums[i]*nums[i]<=nums[j]*nums[j])
             {
                 ans[p] = nums[j] * nums[j];
                 j--;
             }
             else
            {
                ans[p] = nums[i] * nums[i];
                i++;
            }
            p--;
         }
         return ans;
    }
};

暴力:直接用sort快速排序

双指针:用双指针,左右都是最大的,把最大的倒叙放入一个新的数组中

四、长度最小的子数组(滑动窗口,核心也是双指针)

(核心是移动起始位置)

滑动窗口: 不断的调节子序列的起始位置和终止位置,从而得出我们要想的结果

(1)209. 长度最小的子数组

209. 长度最小的子数组icon-default.png?t=N7T8https://leetcode.cn/problems/minimum-size-subarray-sum/

class Solution {
public:
    int minSubArrayLen(int target, vector<int>& nums) {
    int  sum = 0;//定义数组和
    int  result = INT32_MAX;
    int  i = 0;//定义起始指针
    int  length = 0;//定义滑动窗口长度
    for(int j = 0;j<nums.size();j++)
    {
        sum += nums[j];
        while(sum >= target)
        {
           length = (j-i+1);
           result = result < length ? result : length;
           sum -= nums[i++];
        }

    }
return result == INT32_MAX ? 0 :result;
    }
};

while (sum >= s) {

subLength = (j - i + 1); // 取子序列的长度

result = result < subLength ? result : subLength;

sum -= nums[i++]; // 这里体现出滑动窗口的精髓之处,不断变更i(子序列的起始位置)}

补充:INT32_MAX

(2)904. 水果成篮

904. 水果成篮icon-default.png?t=N7T8https://leetcode.cn/problems/fruit-into-baskets/

class Solution {
public:
    int totalFruit(vector<int>& fruits) {
    int l= 0;
    int r =0;
    int ans = 2;
    //定义两个篮子 
    int ln = fruits[l];
    int rn = fruits[r];
    while(r < fruits.size())
    {
        if(fruits[r] == rn||fruits[r] == ln )
        {
            ans = max (r-l+1,ans);
            r++;
        }
    //滑动
  else//当第三种出现
    {
          l =r - 1;
          ln = fruits[l];//这时候第三种就做rn
         while (l>=1 && fruits[l-1] == ln) l--;
            rn = fruits[r];
            ans = max (ans,r-l+1);
         
    }
    }
    return ans;
    }
};

滑动窗口,如何移动起始指针,是直接找到r,然后慢慢往回找 

可以用到哈希表(复刷一遍)

五、螺旋矩阵(模拟)

是一个模拟的过程,注意左开右闭(循环不变量原则)

(1)59. 螺旋矩阵2

59. 螺旋矩阵 IIicon-default.png?t=N7T8https://leetcode.cn/problems/spiral-matrix-ii/

class Solution {
public:
    vector<vector<int>> generateMatrix(int n) {
//定义一个n*n 的二维数组
     vector<vector<int>> res(n,vector<int>(n,0));
//定义起始位置
     int startx = 0;
     int starty = 0;
     int loop = n/2;//圈数 
     int offset = 1;//补偿数量
     int count = 1;
     int mid = n/2;
     int i,j;
     while(loop--)
     {
         i = startx;
         j = starty; 
//从左到右
     for(j = starty; j < n-offset; j++)
     {
         res[i][j] = count++;
     }
//从上到下
     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[mid][mid] = count;
}
return res;
    }
};

1.四个循环模拟的过程需要注意

2. 定义二维数组n*n的形式  vector<vector<int>> res(n,vector<int>(n,0));

3.考虑边长是奇数个时,考虑mid

(2)54. 螺旋矩阵

54. 螺旋矩阵icon-default.png?t=N7T8https://leetcode.cn/problems/spiral-matrix/

class Solution {
public:
    vector<int> spiralOrder(vector<vector<int>>& matrix) {
//判断行列矩阵是否为空
     if(matrix.size() == 0 || matrix[0].size() == 0) return {};
int rows = matrix.size();int cols = matrix[0].size();
int n = rows * cols;
vector<int> res(n);//定义一个一维数组存放结果
int startx = 0,starty = 0;
int loop = min(rows,cols) / 2;
int mid = min(rows,cols) / 2;
int i,j;
int offset = 1;
int count = 0;
while(loop--)
{
    i = startx;
    j = starty;
//从左向右
    for(j = starty; j < cols - offset; j++)
    {
        res[count++] = matrix[i][j];
    }
//从上到下
    for(i = startx; i < rows - offset; i++)
    {
        res[count++] = matrix[i][j];
    }
//右到左
    for(; j > starty; j--)
    {
        res[count++] = matrix[i][j];
    }
//从下到上
    for(; i > startx; i--)
    {
        res[count++] = matrix[i][j];
    }
     startx++;
     starty++;
     offset++;
}
     if(min(cols,rows) % 2)
     {
         if(rows > cols){
             for(int i = mid; i < mid + rows - cols + 1; ++i){
                 res[count++] = matrix[i][mid];
             }
         }
         else {
               for(int i = mid; i < mid + cols - rows + 1; ++i){
                 res[count++] = matrix[mid][i];
             }
         }
     }
     return res;
    }
};

和上一题一样都为模拟的过程,但是又区别

1.圈数不一样,这个题目为min(cols,rows)/2;//rows是行数,cols是列数

2.mid不一样

3.考虑的特殊情况不一样,此题当min(cols,rols)为奇数时,需考虑剩下的部分数值如何填充

4.  if(matrix.size() == 0 || matrix[0].size() == 0) return {};//判断矩阵是否为空的操作

  • 5
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

A_SHOWY

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值