• 模拟问题(上)


    一、旋转数组

    解法一:额外数组

    可以使用额外的数组来将每个元素放至正确的位置。遍历原数组,将原数组下标为 i 的元素放至新数组下标为 (i+m) mod n (为了防止右移的长度大于数组的长度,所以才有取余)的位置,最后返回新数组即可

    class Solution {
    public:
        /**
         * 旋转数组
         * @param n int整型 数组长度
         * @param m int整型 右移距离
         * @param a int整型vector 给定数组
         * @return int整型vector
         */
        vector<int> solve(int n, int m, vector<int>& a) {
            // write code here
            vector<int>res(a.size());
            for(int i=0;i<n;i++)
                res[(i+m)%n]=a[i];
            return res;
        }
    };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    时间复杂度 O(n):其中 n 为数组的长度,遍历数组时间O(n)
    空间复杂度O(n): 额外新数组占用空间

    解法二:三步翻转法(推荐)

    循环右移相当于从第m个位置开始,左右两部分视作整体翻转。即abcdefg右移3位efgabcd可以看成AB翻转成BA(这里小写字母看成数组元素,大写字母看成整体)。既然是翻转我们就可以用到reverse函数。

    • 因为m可能大于n,因此需要对n取余,因为每次长度为n的旋转数组相当于没有变化。
    • 第一次将整个数组翻转,得到数组的逆序,它已经满足了右移的整体出现在了左边。
    • 第二次就将左边的m个元素单独翻转,因为它虽然移到了左边,但是逆序了。
    • 第三次就将右边的n−m个元素单独翻转,因此这部分也逆序了。
      请添加图片描述
    class Solution {
    public:
        vector<int> solve(int n, int m, vector<int>& a) {
            //取余,因为每次长度为n的旋转数组相当于没有变化
            m = m % n; 
            //第一次逆转全部数组元素
            reverse(a.begin(), a.end()); 
            //第二次只逆转开头m个
            reverse(a.begin(), a.begin() + m); 
            //第三次只逆转结尾m个
            reverse(a.begin() + m, a.end()); 
            return a;
        }
    };
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    时间复杂度:O(n),三次reverse函数的复杂度都最坏为O(n)
    空间复杂度:O(1),没有使用额外的辅助空间

    二、螺旋矩阵

    解法:边界模拟法

    这道题就是一个简单的模拟,我们想象有一个矩阵,从第一个元素开始,往右到底后再往下到底后再往左到底后再往上,结束这一圈,进入下一圈螺旋。

    • 首先排除特殊情况,即矩阵为空的情况。
    • 设置矩阵的四个边界值,开始准备螺旋遍历矩阵,遍历的截止点是左右边界或者上下边界重合。
    • 首先对最上面一排从左到右进行遍历输出,到达最右边后第一排就输出完了,上边界相应就往下一行,要判断上下边界是否相遇相交。
    • 然后输出到了右边,正好就对最右边一列从上到下输出,到底后最右边一列已经输出完了,右边界就相应往左一列,要判断左右边界是否相遇相交。
    • 然后对最下面一排从右到左进行遍历输出,到达最左边后最下一排就输出完了,下边界相应就往上一行,要判断上下边界是否相遇相交。
    • 然后输出到了左边,正好就对最左边一列从下到上输出,到顶后最左边一列已经输出完了,左边界就相应往右一列,要判断左右边界是否相遇相交。
    • 重复上述3-6步骤直到循环结束。

    请添加图片描述

    class Solution {
    public:
        vector<int> spiralOrder(vector<vector<int> > &matrix) {
            vector<int> res;
            int n = matrix.size();
            //先排除特殊情况
            if(n == 0) 
                return res;
            //左边界
            int left = 0; 
            //右边界
            int right = matrix[0].size() - 1; 
            //上边界
            int up = 0; 
            //下边界
            int down = n - 1; 
            //直到边界重合
            while(left <= right && up <= down){ 
                //上边界的从左到右
                for(int i = left; i <= right; i++) 
                    res.push_back(matrix[up][i]); 
                //上边界向下
                up++; 
                if(up > down)
                    break;
                //右边界的从上到下
                for(int i = up; i <= down; i++) 
                    res.push_back(matrix[i][right]);
                //右边界向左
                right--; 
                if(left > right)
                    break;
                //下边界的从右到左
                for(int i = right; i >= left; i--) 
                    res.push_back(matrix[down][i]);
                //下边界向上
                down--; 
                if(up > down)
                    break; 
                //左边界的从下到上
                for(int i = down; i >= up; i--) 
                    res.push_back(matrix[i][left]);
                //左边界向右
                left++; 
                if(left > right)
                    break;
            }
            return res;
        }
    };
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51

    时间复杂度:O(mn),相当于遍历整个矩阵
    空间复杂度:O(1),res属于必要空间,没有使用额外辅助空间

  • 相关阅读:
    60 条 rsync 常用命令及其说明
    CSS 实现航班起飞、飞行和降落动画
    REDIS7.X哨兵模式
    kubeadm下进行etcd数据备份与还原
    【微信小程序 | 实战开发】常用的基础内容组件介绍和使用(2)
    华为服务器安装操作系统
    【从零开始学爬虫】采集谷歌网页列表数据
    《快速掌握QML》第五章 组件
    华为发布鸿蒙开发套件 全面加速推进鸿蒙生态
    数据结构线性表之双链表
  • 原文地址:https://blog.csdn.net/qwer1234mnbv_/article/details/126063701