【Day2】数组Part2

【Day2】数组Part2

209. 长度最小的子数组

  1. 思路:

    落实到代码中时,要分两部分实现:右指针不断前进,它每前进一步后、又要等待左指针是否要追过来。具体的:

    • 当窗口不再符合要求时,右指针才继续前进。
    • 当窗口符合了要求之后,右指针就要开始追过来,直到窗口不再符合要求。

    注意:(几点概括)

    滑动窗口的核心思想是:寻找符合题目要求的最大窗口(亦即——最长子串)。

    具体来说:

    • 前提:保持扩展/收缩方向一致、不变;
    • 重点:讲题目中的描述种种要求总结为 —— 要什么样的最长子串条件才是中心需求
    • 注意:什么时候进行子串的记录?—— 在子串符合题目要求的时候进行记录。
  2. 代码:

    class Solution {
    public:
        int minSubArrayLen(int target, vector<int>& nums) {
            int l = 0;
            int smallest = nums.size() + 1;
            int sum = 0;
            // 窗口前进
            for (int r = 0; r < nums.size(); r++) {
                sum += nums[r];
                while (sum >= target) {
                    // 先记录再行动
                    int len = r - l + 1;
                    if (smallest > len) {
                        smallest = len;
                    }
                    sum -= nums[l++]; // 窗口缩减
                }
                cout << l << " " << r << " " << sum << endl;
            }
            return smallest == nums.size() + 1 ? 0 : smallest;
        }
    };
    
  3. 练习:

    904. 水果成篮

    class Solution {
    public:
        int totalFruit(vector<int>& fruits) {
            int len = fruits.size();
            int l = 0;
            unordered_map<int, int> types;
            int max_len = 0;
            for (int r = 0; r < len; r++) {
                int type_r = fruits[r];
                if (types.count(type_r)) {
                    types[type_r]++;
                } else {
                    types[type_r] = 1;
                }
                // 当种类多于2个,开始收缩窗口
                while (types.size() > 2 && l < len) {
                    int type_l = fruits[l++];
                    if (types[type_l]) {
                        types[type_l]--;
                        if (types[type_l] == 0) {
                            types.erase(type_l);
                        }
                    }
                }
                if (types.size() <= 2) {
                    int sum = r - l + 1;
                    max_len = sum > max_len ? sum : max_len;
                }
            }
            return max_len;
        }
    };
    

54. 螺旋矩阵

  1. 思路:

    可以通过"指南针"方法(存储不同方向的坐标变化量,循环中只需要根据不同条件进行方向变化即可)进行模拟行走路线、避免过于繁杂的判断和计算。

    • 注意对已访问元素的标记,可以用vector<vector<bool>>数组进行记录,性价比较高。
  2. 代码:

    class Solution {
    private:
        pair<int, int> directions[4] = {{0, 1}, {1, 0}, {0, -1}, {-1, 0}};
    
    public:
        vector<int> spiralOrder(vector<vector<int>>& matrix) {
            if (matrix.empty() || matrix[0].empty())
                return {}; // 处理空矩阵
    
            int len_r = matrix.size();
            int len_c = matrix[0].size();
            vector<vector<bool>> visited(
                len_r, vector<bool>(len_c, false)); // 标记已访问的单元格
            
            int i = 0, j = 0;
            int cur_der = 0;
            vector<int> result;
    
            while (result.size() < len_r * len_c) {
                result.push_back(matrix[i][j]);
                visited[i][j] = true; // 标记当前单元格为已访问
                cout << matrix[i][j] << " ";
    
                // 要碰到边界or新的一步已访问过 ——> 切换方向
                int next_i = i + directions[cur_der].first;
                int next_j = j + directions[cur_der].second;
                if (next_i < 0 || next_i >= len_r || next_j < 0 ||
                    next_j >= len_c || visited[next_i][next_j]) {
                    cur_der = (cur_der + 1) % 4;
                }
                // 更新当前位置
                i +=  directions[cur_der].first;
                j +=  directions[cur_der].second;
            }
            return result;
        }
    };
    
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值