【LeetCode 刷题笔记】12、13、14

12.水果成篮(904)

题目

你正在探访一家农场,农场从左到右种植了一排果树。这些树用一个整数数组 fruits 表示,其中 fruits[i] 是第 i 棵树上的水果 种类

你想要尽可能多地收集水果。然而,农场的主人设定了一些严格的规矩,你必须按照要求采摘水果:

  • 你只有 两个 篮子,并且每个篮子只能装 单一类型 的水果。每个篮子能够装的水果总量没有限制。
  • 你可以选择任意一棵树开始采摘,你必须从 每棵 树(包括开始采摘的树)上 恰好摘一个水果 。采摘的水果应当符合篮子中的水果类型。每采摘一次,你将会向右移动到下一棵树,并继续采摘。
  • 一旦你走到某棵树前,但水果不符合篮子的水果类型,那么就必须停止采摘。

给你一个整数数组 fruits ,返回你可以收集的水果的 最大 数目。

示例 1:

输入:fruits = [1,2,1]
输出:3
解释:可以采摘全部 3 棵树。

示例 2:

输入:fruits = [0,1,2,2]
输出:3
解释:可以采摘 [1,2,2] 这三棵树。
如果从第一棵树开始采摘,则只能采摘 [0,1] 这两棵树。

示例 3:

输入:fruits = [1,2,3,2,2]
输出:4
解释:可以采摘 [2,3,2,2] 这四棵树。
如果从第一棵树开始采摘,则只能采摘 [1,2] 这两棵树。

示例 4:

输入:fruits = [3,3,3,1,2,1,1,2,3,3,4]
输出:5
解释:可以采摘 [1,2,1,1,2] 这五棵树。

提示:

  • 1 <= fruits.length <= 105
  • 0 <= fruits[i] < fruits.length

思路及题解

解法一 滑动窗口
  • 本题本质为求只有两种元素的最长子数组大小,考虑用滑动窗口
  • 左指针和右指针表示满足条件的窗口的左右边界
  • 哈希表来存储每个数字及其出现的次数(原先有考虑最后一个元素出现的位置、用count变量记录元素出现的次数等想法,但均难以实现,以后有键-值对形式的数据考虑用哈希表)
  • 当哈希表中的元素小于等于两个时,右指针不断向右移动,同时将指向的数字填入哈希表中
  • 当哈希表中的元素数量大于2,即出现了第3种数字时,将左指针指向的数字一个个删除,直到某个数字被删完为止,这时的数组为新的满足条件的子数组
  • 注意题目条件,当遇到第三个数字时即结束遍历,即使后面还有在这两种数字之中的数字,也不能计数
class Solution {
public:
    int totalFruit(vector<int>& fruits) {
        int n = fruits.size();
        map<int, int> m;

        int left = 0, ans = 0;
        for (int right = 0; right < n; right++) {
            m[fruits[right]]++;
            while (m.size() > 2) {
                map<int, int>::iterator pos = m.find(fruits[left]);
                //注意这里pos是迭代器,不能写pos--
                pos->second--;
                if (pos->second == 0) {
                    m.erase(pos);
                }
                left++;
            }
            ans = max(ans, right - left + 1);
        }
        return ans;
    }
};

13.螺旋矩阵 II(59)

题目

给你一个正整数 n ,生成一个包含 1n2 所有元素,且元素按顺时针顺序螺旋排列的 n x n 正方形矩阵 matrix

示例 1:

img

输入:n = 3
输出:[[1,2,3],[8,9,4],[7,6,5]]

示例 2:

输入:n = 1
输出:[[1]]

提示:

  • 1 <= n <= 20

思路及题解

解法一 模拟
  • 这道题关键是明白循环不变量是什么
  • 可以将螺旋矩阵拆分为一次又一次地转圈,一共需要转 n/2 圈
  • 确定边界条件尤为重要,分清楚每边是左闭右闭还是左闭右开等,并在每次转圈保持一致,不能这边是一种方式,另外一边又是一种方式,转着转着就转晕了
  • 需要注意的是n2为奇数时,最中心的数没有遍历到,需要在最后做一个判断,手动加入
  • 这种题直接大胆写代码,在数学上分析、再画图等容易晕
  • 真正解决题目的代码都是简洁的,或者有原则性的,而不是一波波的判断,拆了东墙补西墙,代码十分冗余

//这里是左闭右开的写法
class Solution {
public:
    vector<vector<int>> generateMatrix(int n) {
        //注意vector创建二维数组的方法
        vector<vector<int>> array(n, vector<int>(n, 0));
        //startx 、 starty表示每次新的转圈开始时,行号和列号的起始值
        //offset 意为“抵消”,在这里控制每次转圈到达的范围
        //count 用于填充数字
        int times = 0, startx = 0, starty = 0, offset = 1, count = 1;
        int i = 0, j = 0;
        //times记录绕圈的次数,达到n/2时退出while
        while (times < n / 2) {
            //注意要初始化i和j,如果只在前两个循环初始化,遍历到前两个循环不执行时,后面两个循环就会出错
            i = startx, j = starty;
            //下面四个for为模拟转了一圈
            // 模拟填充上行从左到右(左闭右开)
            for (; j < n - offset; j++)
                array[i][j] = count++;
            // 模拟填充右列从上到下(左闭右开)
            for (; i < n - offset; i++)
                array[i][j] = count++;
            // 模拟填充下行从右到左(左闭右开)
            for (; j > starty; j--)
                array[i][j] = count++;
            // 模拟填充左列从下到上(左闭右开)
            for (; i > startx; i--)
                array[i][j] = count++;
            //变量均加一
            // 第二圈开始的时候,起始位置要各自加1
            startx++;
            starty++;
            times++;
            offset++;
        }
        //n^2^为奇数时特殊判断
        if (n % 2)
            array[n / 2][n / 2] = n * n;
        return array;
    }
};

14.螺旋矩阵(54)

题目

给你一个 mn 列的矩阵 matrix ,请按照 顺时针螺旋顺序 ,返回矩阵中的所有元素。

示例 1:

img

输入:matrix = [[1,2,3],[4,5,6],[7,8,9]]
输出:[1,2,3,6,9,8,7,4,5]

示例 2:

img

输入:matrix = [[1,2,3,4],[5,6,7,8],[9,10,11,12]]
输出:[1,2,3,4,8,12,11,10,9,5,6,7]

提示:

  • m == matrix.length
  • n == matrix[i].length
  • 1 <= m, n <= 10
  • -100 <= matrix[i][j] <= 100

思路及题解

解法一 模拟
  • 和上题的思路一模一样,注意循环不变量即可
  • 由于题目要求的结果与上题不同,这里while的循环条件需要变化
  • 同样,当矩阵为 n*n 且 n2为奇数时,最后一个数填不进去,需要额外进行判断
class Solution {
public:
    vector<int> spiralOrder(vector<vector<int>>& matrix) {
        //注意 matrix 为空的情况
        if(array.size() == 0 || array[0].size() == 0) return {};
        int startx = 0, starty = 0, m = matrix.size(), n = matrix[0].size();
        vector<int> ans;
        //当ans的大小达到max值时,所有数字都已经填入,结束遍历
        int i, j, offset = 1, max = m * n;
		//当矩阵为 n*n 且 n^2^为奇数时,最后一个数填不进去,max值在原来基础上减一
        if (m == n && m % 2 == 1)
            max--;

        while (ans.size() < max) {
            i = startx;
            j = starty;
            for (; j < n - offset && ans.size() < max; j++)
                ans.push_back(matrix[i][j]);
            for (; i < m - offset && ans.size() < max; i++)
                ans.push_back(matrix[i][j]);
            //注意这里是 j > starty,而不是 j >= starty
            for (; j > starty && ans.size() < max; j--)
                ans.push_back(matrix[i][j]);
            for (; i > startx && ans.size() < max; i--)
                ans.push_back(matrix[i][j]);

            startx++;
            starty++;
            offset++;
        }
        if (m == n && m % 2 == 1)
            //把最后一个数加上,中间的数是 matrix [m / 2][n / 2]
            ans.push_back(matrix[m / 2][n / 2]);
        return ans;
    }
};

  • 25
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值