leetcode代码随想录数组篇

704.二分查找:

由于数组是严格升序 (无重复或有重复均可,但有序),我们可以使用二分查找高效定位目标值。

核心思想:

  • 设置两个指针 leftright,分别指向数组的起始和末尾。

  • 每次取中间位置 mid = left + (right - left) / 2(避免整型溢出)。

  • 比较 nums[mid]target

    • 若相等 → 找到目标,返回 mid
    • nums[mid] > target → 目标在左半部分,令 right = mid - 1
    • nums[mid] < target → 目标在右半部分,令 left = mid + 1
  • left > right 时,说明未找到,返回 -1

    class Solution {
    public:
    int search(vector<int>& nums, int target) {
    int left = 0, right = nums.size()-1;
    while(left<=right){
    int mid = left + (right-left)/2;
    if(nums[mid]>target){
    right = mid -1;
    }else if(nums[mid]<target){
    left = mid+1;
    }else return mid;
    }
    return -1;
    }
    };

27.移除数组:

解题思路:双指针(快慢指针)

这是一个经典的 原地修改数组 问题,非常适合使用 双指针技巧

核心思想:

  • 使用两个指针:

    • 快指针 fast:遍历整个数组,逐个检查每个元素。
    • 慢指针 slow:指向"下一个应该保留的位置"。
  • nums[fast] != val 时,说明这个元素需要保留,就把它复制到 nums[slow],然后 slow++

  • 最终,slow 的值就是新数组的长度。

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

977.有序数组的平方

解题思路:双指针(从两端向中间)

关键观察:

  • 原数组是升序排列,但包含负数。
  • 平方后,最大值一定出现在两端(最左或最右),因为绝对值最大的数在两端。
  • 因此,我们可以使用双指针分别指向首尾 ,比较它们的平方,从结果数组的末尾开始填入较大者

算法步骤:

  1. 创建一个长度为 n 的结果数组 result
  2. 初始化:
    • 左指针 i = 0
    • 右指针 j = n - 1
    • 填充位置 k = n - 1(从后往前填)
  3. i <= j 时循环:
    • 如果 nums[i]^2 <= nums[j]^2,说明右边更大,把 nums[j]^2 放入 result[k]j--
    • 否则,把 nums[i]^2 放入 result[k]i++
    • 每次操作后 k--
  4. 返回 result

💡 这种"逆向填充"保证了结果数组天然有序(从小到大),无需额外排序。

209. 长度最小的子数组

解题思路:滑动窗口(双指针)

为什么能用滑动窗口?

  • 所有元素 > 0 → 窗口扩大时,和单调递增;窗口缩小时,和单调递减。
  • 因此,一旦当前窗口和 ≥ s,就可以尝试 收缩左边界 来寻找更短的满足条件的子数组。

算法流程:

  1. 初始化:

    • i = 0:窗口左边界
    • sum = 0:当前窗口和
    • result = INT32_MAX:记录最小长度
  2. 右指针 j 从 0 遍历到末尾:

    • nums[j] 加入窗口(sum += nums[j]
    • 只要 sum >= s,就不断收缩左边界while 循环):
      • 计算当前窗口长度 j - i + 1
      • 更新 result
      • 减去 nums[i] 并右移 i
  3. 最终若 result 仍为初始值,说明无解,返回 0;否则返回 result

    class Solution {
    public:
    int minSubArrayLen(int target, vector<int>& nums) {
    int result = INT32_MAX;
    int sum = 0;
    int sublen = 0;
    int i = 0;
    for(int j = 0; j < nums.size();j++){
    sum += nums[j];
    while(sum>=target){
    sublen = j-i+1;
    result = result < sublen ? result:sublen;
    sum -=nums[i++];
    }
    }
    return result == INT32_MAX?0:result;
    }
    };

59螺旋矩阵

给定一个正整数 n,生成一个 n × n 的矩阵,使得矩阵中的元素从 1 到 n²顺时针螺旋顺序 填充。

核心观察:螺旋 = 一圈一圈地填

想象你在画一个正方形的"回"字:

  • 先画最外层(第1圈),
  • 再画里面一层(第2圈),
  • 直到中心(如果 n 是奇数,中心剩一个格子)。

每一圈都由 四条边 组成:

  1. 上边:从左 → 右
  2. 右边:从上 → 下
  3. 下边:从右 → 左
  4. 左边:从下 → 上

✅ 关键技巧:每条边都采用"左闭右开"区间(即包含起点,不包含终点),这样四个角不会重复填写!

算法设计要点

1. 圈数

  • 总共要循环 loop = n / 2 圈。
  • 例如:n=5 → loop=2(填两圈),中间 (2,2) 单独处理。

2. 每圈的起始位置

  • 第1圈:从 (0, 0) 开始
  • 第2圈:从 (1, 1) 开始
  • 第k圈:从 (k-1, k-1) 开始 → 用 startx, starty 记录

3. 每条边的边界控制

  • offset 控制"右边界"或"下边界"。
  • 第1圈:右边到 n - 1(即 n - offset,offset=1)
  • 第2圈:右边到 n - 2(offset=2)
  • 所以每次循环后 offset++

4. 填充顺序(左闭右开)

复制代码
上边:(startx, starty) → (startx, n - offset - 1)
右边:(startx, n - offset) → (n - offset - 1, n - offset)
下边:(n - offset, n - offset) → (n - offset, starty + 1)
左边:(n - offset, starty) → (startx + 1, starty)

5. 奇数中心处理

  • 如果 n 是奇数,最中心 (mid, mid) 没被填,最后填入 count(此时 count == n²)

💡 为什么用"左闭右开"?

避免四个角被重复填写!

比如 n=3:

  • 如果上边填 [0][0][0][2](包含3),
  • 右边又从 [0][2] 开始填,
  • 那么 [0][2] 就被写了两次!

而"左闭右开":

  • 上边填 [0][0], [0][1](停在 [0][2] 前)

  • 右边从 [0][2] 开始填 → 完美衔接,无重叠!

    vector<vector<int>> generateMatrix(int n) {
    vector<vector<int>> res(n, vector<int>(n, 0));
    int startx = 0, starty = 0; // 每圈起点
    int loop = n / 2; // 圈数
    int mid = n / 2; // 中心点(n为奇数时用)
    int count = 1; // 当前要填的数字
    int offset = 1; // 控制边界收缩

    复制代码
      while (loop--) {
          int i = startx, j = starty;
    
          // 1. 上行:左 → 右(左闭右开)
          for (; j < n - offset; j++) res[i][j] = count++;
    
          // 2. 右列:上 → 下(左闭右开)
          for (; i < n - offset; i++) res[i][j] = count++;
    
          // 3. 下行:右 → 左(左闭右开)
          for (; j > starty; j--)     res[i][j] = count++;
    
          // 4. 左列:下 → 上(左闭右开)
          for (; i > startx; i--)     res[i][j] = count++;
    
          // 进入内圈
          startx++;
          starty++;
          offset++;
      }
    
      // 处理奇数中心
      if (n % 2 == 1) res[mid][mid] = count;
    
      return res;

    }

58. 区间和

复制代码
#include<iostream>
#include<vector>

using namespace std;

int main(){
    int n, a,b;
    cin>>n;
    vector<int>res(n,0);
    vector<int>p(n,0);

    int prevec = 0; 
    for(int i = 0; i<n ; i++){
        cin>>res[i];
        prevec += res[i];
        p[i] = prevec;
    }
    while(cin>>a>>b){
        int sum ;
        if(a == 0) sum = p[b];
        else sum = p[b]-p[a-1];
        cout<<sum<<endl;
    }

}

44. 开发商购买土地

一、题目理解

  • 有一个 n × m 的网格,每个格子有权值(土地价值)。
  • 只能切一刀 :要么横向切 (水平方向,分成上下两块),要么纵向切(垂直方向,分成左右两块)。
  • 切完后,两部分都必须非空(即不能在最外侧切)。
  • 目标:使两部分的总价值之差的绝对值最小

解题思路

  1. 先算出整个网格的总和 sum

  2. 尝试所有合法的横向切割位置 (共 n-1 种):

    • 上半部分和 = 前 k 行之和
    • 下半部分和 = sum − 上半部分和
    • 差 = |sum − 2 × 上半部分和|
  3. 尝试所有合法的纵向切割位置 (共 m-1 种):

    • 左半部分和 = 前 l 列之和
    • 右半部分和 = sum − 左半部分和
    • 差 = |sum − 2 × 左半部分和|
  4. 取所有可能中的最小差。

    #include<iostream>
    #include<vector>
    #include<climits>

    using namespace std;
    int main(){
    int n,m;
    cin>>n>>m;
    vector<vector<int>>vec(n,vector<int>(m,0));
    int sum =0;
    for(int i = 0; i<n;i++){
    for(int j =0; j<m;j++){
    cin>>vec[i][j];
    sum+=vec[i][j];
    }
    }
    //计算横向
    vector<int>vectical(m,0);
    for(int i =0;i<m;i++){
    for(int j =0; j<n;j++){
    vectical[i]+=vec[i][j];
    }
    }
    //计算纵向
    vector<int>horizontal(n,0);
    for(int j =0; j<n;j++){
    for(int i =0;i<m;i++){
    horizontal[j]+=vec[i][j];
    }
    }

    复制代码
     int result =INT_MAX;
     int vectcutsum=0;
     for(int i =0;i<m;i++){
         vectcutsum+=vectical[i];
         result=min(result,abs(sum-vectcutsum-vectcutsum));
     }
    
     int horcutsum=0;
     for(int j =0;j<n;j++){
         horcutsum+=horizontal[j];
         result=min(result,abs(sum-horcutsum-horcutsum));
     }
    
     return result;

    }

相关推荐
Remember_9932 小时前
【LeetCode精选算法】位运算专题一
java·开发语言·数据结构·leetcode·哈希算法
MicroTech20252 小时前
微算法科技(NASDAQ :MLGO)量子生成对抗网络(QGAN)技术,为网络安全防御提供了全新的技术路径
科技·算法·生成对抗网络
YuTaoShao2 小时前
【LeetCode 每日一题】3507. 移除最小数对使数组有序 I
算法·leetcode·职场和发展
LYS_06182 小时前
RM赛事C型板九轴IMU解算(3)(姿态融合算法)
c语言·算法·imu·姿态解算·四元数到欧拉角
LDG_AGI2 小时前
【机器学习】深度学习推荐系统(三十一):X For You Feed 全新推荐系统技术架构深度解析
人工智能·深度学习·算法·机器学习·架构·推荐算法
tobias.b2 小时前
408真题解析-2010-5-数据结构-树的结点数量计算
数据结构·算法·408真题解析
chilavert3183 小时前
技术演进中的开发沉思-329 JVM:垃圾回收(中)
java·jvm·算法
啊阿狸不会拉杆3 小时前
《机器学习》 第 9 章 - 深度强化学习
人工智能·算法·机器学习·计算机视觉·ai·ml
仰泳的熊猫3 小时前
题目 1429: 蓝桥杯2014年第五届真题-兰顿蚂蚁
数据结构·c++·算法·蓝桥杯