2023秋招面试准备

2023-05-16

2022 秋招资料

算法数据结构

螺旋矩阵问题

螺旋矩阵I(将 1~n*m 个数按蛇形方向填入数组中)

记录蛇形矩阵偏移量方法,四个不同方向右下左上,判断什么情况下矩阵遍历完,1.要么出界 2.要么走完

class Solution {
public:
    vector<int> spiralOrder(vector<vector<int>>& matrix) {
        int n = matrix.size(), m = matrix[0].size();
        int dir[4][2] = {0, 1, 1, 0, 0, -1, -1, 0};
        vector<int> res;
        vector<vector<bool>> vis(n, vector<bool>(m));
        for (int i = 0, x = 0, y = 0, d = 0; i < n * m; i ++) {
            res.push_back(matrix[x][y]);
            vis[x][y] = true;
            int nx = x + dir[d][0], ny = y + dir[d][1];
            if (nx < 0 || nx >= n || ny < 0 || ny >= m || vis[nx][ny]) {
                d = (d + 1) % 4;
                nx = x + dir[d][0], ny = y + dir[d][1];
            }
            x = nx, y = ny;
        }

        return res;
    }
};

螺旋矩阵 II

desc: 给定 n 生成一个包含一到 n^2的矩阵, 按照螺旋矩阵的方式存储

解法:和螺旋矩阵 I 类似,通过偏移量构造

class Solution {
public:
    vector<vector<int>> generateMatrix(int n) {
        vector<vector<int>> res(n, vector<int>(n, 0));
        int dir[4][2] = {0, 1, 1, 0, 0, -1, -1, 0};
       for (int x = 0, y = 0, cnt = 1, d = 0; cnt <= n * n; cnt ++) {
           res[x][y] = cnt;
           int nx = x + dir[d][0], ny = y + dir[d][1];
           if (nx < 0 || nx >= n || ny < 0 || ny >= n || res[nx][ny]) {
               d = (d + 1) % 4;
               nx = x + dir[d][0], ny = y + dir[d][1];
           }
           x = nx, y = ny;
       } 
        return res;
    }
};

螺旋矩阵 III

desc:给定一个nxm的矩阵,和一个开始走的起点坐标,求螺旋方向走的坐标,并且可以出界, 如下图所示

class Solution {
public:
    vector<vector<int>> spiralMatrixIII(int n, int m, int x, int y) {
        vector<vector<int>> res;
        int tot = n * m;
        res.push_back({x, y});
        int d = 0;
        int dir[4][2] = {0, 1, 1, 0, 0, -1, -1, 0};
        // k 循环表示模拟圆环的半径, 有一个规律1, 1, 2, 2, 3, 3...
        for (int k = 1; res.size() < tot; k ++) {
            // i 循环表示矩阵是按照每个半径会走两次
            for (int i = 0; i < 2 && res.size() < tot; i ++) {
                // j循环表示开始走半径为 k 的元素
                for (int j = 0; j < k && res.size() < tot; j ++) {
                        int nx = x + dir[d][0], ny = y + dir[d][1];
                        // 在矩阵内即可添加进去
                        if (nx >= 0 && nx < n && ny >= 0 && ny < m)
                            res.push_back({nx, ny});
                        x = nx, y = ny;
                }
                d = (d + 1) % 4;
            }
        }
        return res;
    }
};

螺旋矩阵 IV

desc: 给定链表从链表中构建一个蛇形矩阵,和 I、II 的构建方式一样

class Solution {
public:
    vector<vector<int>> spiralMatrix(int n, int m, ListNode* head) {
        vector<vector<int>> res(n, vector<int>(m, -1));
        int dir[4][2] = {0, 1, 1, 0, 0, -1, -1, 0};
        int x = 0, y = 0, d = 0;
        for (auto p = head; p != nullptr; p=p->next) {
            res[x][y] = p->val;
            int nx = x + dir[d][0], ny = y + dir[d][1];
            if (nx < 0 || nx >= n || ny < 0 || ny >= m || res[nx][ny] != -1) {
                d = (d + 1) % 4;
                nx = x + dir[d][0], ny = y + dir[d][1];
            }
            x = nx, y = ny;
        }
        return res;
    }
};

单链表排序问题

单链表快速排序(时间O(nlogn), 空间(O(logn)))

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-oay7AL1b-1662036839548)(/Users/liyan/Library/Application Support/typora-user-images/image-20220831102437989.png)]

链表快排基本思路

  • 选定链表头基准元素
  • 建立三个子链表left,mid,right
    • left存储比基准元素小的节点
    • mid 存储和基准元素相等的节点
    • right 存储比基准元素大的节点
  • 递归的去排序第二个过程
    • 递归出口节点空或者链表只有一个节点
  • 最后将 left 拼接 mid 拼接 right
/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode() : val(0), next(nullptr) {}
 *     ListNode(int x) : val(x), next(nullptr) {}
 *     ListNode(int x, ListNode *next) : val(x), next(next) {}
 * };
 */
class Solution {
public:
    ListNode* getTail(ListNode* head) {
        while (head->next) head=head->next;
        return head;
    }
    ListNode* sortList(ListNode* head) {
        if (!head || !head->next) return head;

        auto left = new ListNode(-1), mid = new ListNode(-1), right = new ListNode(-1);
        auto ltail = left, rtail = right, mtail = mid;
        // int cnt = 0;
        // int val = head->val;
        // for (auto p = head; p; p = p->next) {
        //     cnt ++;
        // }
        // int n = cnt;
        // for (auto p = head; p; p = p->next) {
        //     cnt --;
        //     if (cnt == n / 2) {
        //         val = p->val;
        //         break;
        //     }
            
        // }
        int val = head->val;
        for (auto p = head; p; p=p->next) {
            if (p->val < val) ltail = ltail->next = p;
            else if (p->val == val) mtail = mtail->next = p;
            else rtail = rtail->next = p;
        }
        ltail->next = mtail->next = rtail->next = nullptr;
        left->next = sortList(left->next);
        right->next = sortList(right->next);

        getTail(left)->next = mid->next;
        getTail(left)->next = right->next;
        auto p = left->next;
        delete left;
        delete mid;
        delete right;
        return p;
    }
};

时间复杂度O(nlogn)、空间复杂度O(logn), 疑问:为什么过不了leetcode 原题

可以将基准值随机选取而不是选取头尾节点

单链表排序(归并)(时间:O(nlogn) 空间:常数,迭代)

迭代写法

想法:

  • 先求出要排序的链表结点数 n
  • i 循环控制排序每一个子区间,子区间长度为 1,2,4,8…2^n
  • 定义一个 dummy 节点为初始节点
  • j循环控制合并每个子区间, j + i <= n, j += 2 * i;
  • p 指向合并子区间第一个节点,q 指向合并子区间第二个节点, 通过 while 循环控制
/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode() : val(0), next(nullptr) {}
 *     ListNode(int x) : val(x), next(nullptr) {}
 *     ListNode(int x, ListNode *next) : val(x), next(next) {}
 * };
 */
class Solution {
public:
    ListNode* sortList(ListNode* head) {
        int n = 0; // 记录链表节点个数
        for (auto p = head; p; p = p->next) n ++; 
        auto dummy = new ListNode(-1); // 虚拟头结点,指向排序好的第一个节点
        dummy->next = head; 

        for (int i = 1; i < n; i *= 2) { // 循环 log 层, 小于n是因为等于n时说明所有元素均归并完毕,大于n时同理
            auto cur = dummy; // cur表示准备排序子区间长度为 i 的起始位置
            for (int j = 1; j + i <= n; j += 2 * i) { // j代表每一段的开始,每次将两段有序段归并为一个大的有序段,故而每次+2i
                auto p = cur->next, q = p; // p 是第一段起始位置, q是第二段起始位置
                for (int k = 0; k < i; k ++) q = q->next; 
                int l = 0, r = 0; 
                while (l < i && r < i && p && q) {
                    if (p->val <= q->val) cur = cur->next=p, p = p->next, l ++;
                    else cur = cur->next=q, q = q->next, r ++;
                }
                while (l < i && p) cur = cur->next = p, p = p->next, l ++;
                while (r < i && q) cur = cur->next = q, q = q->next, r ++;
                cur->next = q;
            }
        }
        return dummy->next;
    }
};
递归写法O(nlogn) + 空间O(logn)

通过递归实现链表归并排序,有以下两个环节:

  • 分割 cut 环节: 找到当前链表中点,并从中点将链表断开(以便在下次递归 cut 时,链表片段拥有正确边界);

    • 我们使用 fast,slow 快慢双指针法,奇数个节点找到中点,偶数个节点找到中心左边的节点。
    • 找到中点 slow 后,执行 slow.next = None 将链表切断。
    • 递归分割时,输入当前链表左端点 head 和中心节点 slow 的下一个节点 tmp(因为链表是从 slow 切断的)。
    • cut 递归终止条件: 当head.next == None时,说明只有一个节点了,直接返回此节点。
  • 合并 merge 环节: 将两个排序链表合并,转化为一个排序链表。

    • 双指针法合并,建立辅助ListNode h 作为头部。
    • 设置两指针 left, right 分别指向两链表头部,比较两指针处节点值大小,由小到大加入合并链表头部,指针交替前进,直至添加完两个链表。
    • 返回辅助ListNode h 作为头部的下个节点 h.next。
    • 时间复杂度 O(l + r),l, r 分别代表两个链表长度。
    ListNode* merge(ListNode* l, ListNode* r) {
            ListNode *dummy = new ListNode(-1);
            auto cur = dummy;
            while (l && r) {
                if (l->val <= r->val) cur = cur->next = l, l = l->next;
                else cur = cur->next = r, r=r->next;
            }
            cur->next = (l ? l : r);
            return dummy->next;
        }
        ListNode* sortList(ListNode* head) {
            if (!head || !head->next) return head;
    
            ListNode* fast = head, *slow = head; // 快慢指针找到中间的 cut 节点分为左右两段
            while (fast->next && fast->next->next) {
                fast = fast->next->next;
                slow = slow->next;
            }
            fast = slow;
            slow = slow->next; // cut 的右边的首个节点
            fast->next = nullptr; // fast 是 cut 后的左边的最后一个节点
    
            ListNode* l = sortList(head), *r = sortList(slow);
            return merge(l, r); // 合并
        }
    

单链表排序插入

插入排序 算法的步骤:

  1. 插入排序是迭代的,每次只移动一个元素,直到所有元素可以形成一个有序的输出列表。
  2. 每次迭代中,插入排序只从输入数据中移除一个待排序的元素,找到它在序列中适当的位置,并将其插入。
  3. 重复直到所有输入数据插入完为止。

为了方便处理边界情况,我们建立虚拟头结点,指向原链表头部。
然后扫描原链表,对于每个节点 vv,从前往后扫描结果链表,找到第一个比 vv 大的节点 uu,将 vv 插入到 uu 之前。

时间复杂度分析:一共遍历 nn 个节点,对于每个节点找合适位置时,最多需要遍历 O(n)O(n) 次,所以总时间复杂度是 O(n2)O(n2)。

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode() : val(0), next(nullptr) {}
 *     ListNode(int x) : val(x), next(nullptr) {}
 *     ListNode(int x, ListNode *next) : val(x), next(next) {}
 * };
 */
class Solution {
public:
    ListNode* insertionSortList(ListNode* head) {
        ListNode* dummy = new ListNode(-1);
        while (head) { // head 指向当前待插入的节点
            ListNode* next = head->next;   // next指向下一个循环待插入的节点
            ListNode* p = dummy; // dummy存的是待插入的链表
            while (p->next && p->next->val <= head->val) p = p->next; //找到插入 head 的位置 p

            head->next = p->next; // 将head 插入 p后面
            p->next = head; // 

            head = next; // head更新为下一个循环要插入的节点

        }
        return dummy->next;

    }
};

单链表排序选择

选择排序过程

单链表排序冒泡

单链表排序堆排序

C++语言特性

C++ 中什么时候把析构函数写为虚函数 ?

当一个类为基类,通常其析构函数被声明为虚函数

why ?

因为如果定义基类指针,根据赋值兼容性问题,基类指针可以指向动态生成子类对象的地址,此时子类对象已经被充当基类使用

而在 delete 基类对象时,如果不定义析构函数为虚函数,则不会调用派生类的析构函数,这样就造成内存泄漏了.

C++中可以把构造函数声明为虚函数 ?

不可以。因为虚函数的调用依靠于虚函数表。然而在构造函数执行完时,虚函数表指针才正确初始化

构造函数不可以声明为虚函数,那么可以实现多态 ?

不可以,因为析构函数一旦被调用,虚函数表指针就会被销毁。在构造函数中实现体重也不可能发生多态行为,因为在构造函数执行时,虚函数表指针还没被正确初始化。

计算机网络

Web Server 项目

数据库

操作系统

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

2023秋招面试准备 的相关文章

  • 关于VR的历史及发展

    寒假我看了关于一些虚拟现实的东西 xff0c 并在网上查获了一些资料 xff0c 作出以下归纳总结 xff1a 虚拟现实 xff0c 无法绕开它的历史 xff0c 最早可以追溯到公元前427年的古希腊时代 xff0c 当时的哲学家柏拉图在提
  • linux安装jdk环境(多种方式)

    linux系统通用安装 通过tar gz压缩包安装 此方法适用于绝大部分的linux系统 下载tar gz的压缩包 xff0c 这里使用官网下载 进入 xff1a http www oracle com technetwork java j
  • 线程的生产者和消费者模式

    多个线程同时运行时 xff0c 会产生线程并发可使用同步操作确保数据的安全性 xff0c 如果需要各线程之间交互 xff0c 可是使用线程等待和唤醒模式 xff0c 在这里常用的等待唤醒中经典的模式为 生产者和消费者模式 生产者和消费者由两
  • 获取操作日志记录(springboot+AOP)

    下面是我在公司写操作日志记录的时候的代码使用的aop自定义注解的方式 xff0c 这里记录一下代码希望可以给大家带来一些帮助 xff0c 顺便自己也巩固一下 方便随时取用 Aop注解实现日志的话其实不难 xff0c 我认为只要理解下面三个点
  • ThinkPHP5 SQL注入(select方法)

    ThinkPHP5 SQL注入 xff08 select方法 xff09 漏洞概要初始配置漏洞利用漏洞分析漏洞修复攻击总结 漏洞概要 本次漏洞存在于 Mysql 类的 parseWhereItem 方法中 xff0c 由于程序没有对数据进行
  • Windows下通过PowerShell终端直接制作tar.gz压缩包

    因为工作需要 xff0c 笔者经常要在windows系统里上传多个文件到linux环境上 centos linux下默认支持tar gz压缩格式 xff0c 因此一般都是通过制作tar gz压缩包来传的 原来在Windows下制作tar g
  • 一日一技:Ocelot网关使用IdentityServer4认证

    概述 Ocelot是一个用 NET Core实现的开源API网关技术 IdentityServer4是一个基于OpenID Connect和OAuth2 0的针对ASP NET Core的框架 xff0c 以中间件的形式存在 OAuth是一
  • Android Studio模拟器启动后不停闪烁(未解决)

    问题描述 xff1a Android Studio模拟器启动后不停闪烁 解决方法 xff1a 右侧点击Device Manager打开设备管理 xff0c 点击修改标志 将Graphics 图样 换成Software 软件 xff0c 点击
  • 复杂网络建模的实现(哈工大深圳复杂网络建模课程Project)

    任务 xff1a 1 xff0c 三张不同的网络 xff1a 已知某人的名称 已知某人的家乡 已知某人的方言 分析这三者各自的网络性能 xff08 节点度数分布 平均最短路径长度 集聚系数 xff09 以及动态行为 xff08 在刻意攻击
  • 免登陆Oracle官网下载JDK

    Oracle官网下载JDK 方法一 免登录下载 进入官网 xff0c 选择需要下载的JDK版本 xff0c 这里以JDK8为例 点击下载 xff0c 勾选同意 在正常情况下 xff0c 点击 Download jdk 8u333 windo
  • linux rancher 清理docker容器磁盘空间

    目录说明 var lib docker containers xff1a 是 Docker 在 Linux 系统上默认存储容器信息的目录 在该目录下 xff0c 每个运行的 Docker 容器都有一个单独的目录 xff0c 以容器 ID 命
  • 如何在官网下载COCO数据集

    官网地址 xff1a https cocodataset org download 1 选择下载的数据 xff0c 右键 xff0c 获取下载地址 2 将 http 改为 https 示例获得的下载地址为 xff1a http images
  • 两个互相引用对象的垃圾回收

    部分转自 xff1a 深入理解java虚拟机 一书 判断对象是否存活 1 引用计数算法 给对象添加一个引用计数器 xff0c 每当有一个地方引用它时 xff0c 计数器值就加1 当引用失效时 xff0c 计数器值就减1 任何时刻计数器为0的
  • ssm整合时,通过jdbc.properties文件无法连接mysql问题

    最近在重温ssm框架 在搭建基础的项目进行单元测试时 xff0c 发现无法连接mysql数据库 通过各种查资料终于发现了原因 原始jdbc properties文件 由于username这个属性会被系统的username变量覆盖 xff0c
  • Mysql数据库之左连接left join 右连接right join 内连接inner join

    最近 xff0c 公司的用户达到了700 43 万 xff0c 意味着数据库已经达到700 43 万 xff0c 聊聊傻傻分不清的连接查询吧 xff01 前提 数据库中一共有三个表 class book phone 而且每个数据库表中都有1
  • VMware虚拟机软件,配置Linux Ubuntu操作系统环境,及安装问题总结大全

    文章目录 1 xff1a 前言2 xff1a 基本认识3 下载环境4 xff1a VM虚拟机的安装5 xff1a ubuntu的下载6 xff1a 把ubuntu安装在VM虚拟机上7 VMware Tools工具8 Source insig
  • linux常用命令(Beginner note)

    命令 ls 列出所有文件及文件夹 ls 路径 xff1a 列出所给路径下的所有文件及文件夹 选项 xff1a xff08 可组合使用 xff0c 也可简写组合形式 xff0c 例 xff1a alh xff0c 无先后顺序 xff09 a
  • 利用JS-SDK微信分享接口调用(后端.NET)

    一直都想研究一下JS SDK微信分享的接口调用 xff0c 由于最近工作需要 xff0c 研究了一下 xff0c 目前只是实现了部分接口的调用 xff1b 其他接口调用也是类似的 xff1b 在开发之前 xff0c 需要提前准备一个微信公众
  • Linux文件查找find

    1 find查找概述 为什么要有文件查找 xff0c 因为很多时候我们可能会忘了某个文件所在的位置 xff0c 此时就需要通过find来查找 find命令可以根据不同的条件来进行查找文件 xff0c 例如 xff1a 文件名称 文件大小 文
  • Linux文件打包与压缩

    1 文件打包与压缩 1 什么是文件压缩 将多个文件或目录合并成为一个特殊的文件 比如 搬家 脑补画面 img 2 为什么要对文件进行压缩 xff1f 当我们在传输大量的文件时 xff0c 通常都会选择将该文件进行压缩 xff0c 然后在进行

随机推荐

  • 集中式版本管理SVN与分布式版本管理Git的区别

    集中式版本控制系统SVN CVS 先说集中式版本控制系统 xff0c 版本库是集中存放在中央服务器的 xff0c 而大家工作的时候 xff0c 用的都是自己的电脑 xff0c 所以要先从中央服务器取得最新的版本 xff0c 然后开始工作 x
  • chatgpt Linux 定时任务 清理rancher pod启动服务的日志文件 脚本

    Linux 定时任务执行命令 假设我们想要每隔X分钟 每隔X天 每天X点执行一个脚本文件 xff0c 可以使用 Linux 自带的 cron 工具来创建定时任务 清理步骤 您可以使用 Linux 自带的 cron 工具来创建定时任务 xff
  • Http协议的几种常见状态码

    在开发好了网站后 xff0c 用户通过URL对资源进行操作 xff0c 服务器端要告诉用户交互的结果 xff0c 比如新增资源是成功还是失败了 一个较好的办法就是遵循HTTP协议 xff0c 使用请求响应的HTTP状态码 xff08 Sta
  • 推荐画UML图以及流程图的在线网站Site

    记得当年学UML课程的时候 xff0c 当你还在为了安装Rose而发愁的时候 xff0c 人家都把作业给交了 xff0c 并且现在大多数UML课程都会让学生使用Rational Rose做画图练习 近来 xff0c 做毕业设计需要提供各种流
  • 浙大PTA平台上的题目题解

    记载一些题目的代码 xff0c 之后想要在b站讲题目 xff0c 到时候会把录的视频上传b站 不是大佬 xff0c 是蒟蒻 xff0c 大佬勿喷 xff0c 仅供参考 xff0c 欢迎大家star xff0c qwq 浙大版 C语言程序设计
  • git 入门教程

    想要将一个项目托管到github xff0c 需要进入项目所在文件夹进行git init命令初始化 Git提交代码的基本流程 xff1a 创建或修改 本地文件使用 git add 命令 xff0c 将创建或修改的文件添加到本地的暂存区 xf
  • 博客搬家

    谢谢大家对我的blog的支持 现在本科毕业 xff0c 准备读研 方向大概是机器学习这一块 又是一个新的开始 我想将我读研学习Python以及机器学习 深度学习 以及数据分析处理 大数据等学习教程放在新的blog上 xff1a blog 欢
  • Python多线程笔记(Python_MultiThread)

    4 MultiThreading 多线程 使用 xff1a a 什么是多线程 xff1f 简单明了 xff0c 让计算机在同一时间内同时运行多个程序 xff0c 并且每个程序的计算互不干扰 xff0c 我们称这样的操作为多线程运算 b ad
  • Python多进程笔记(Python_MultiProcess)

    1 MutiProcessing 多进程 使用 xff1a a 什么是多进程 xff1f 在上面我们使用多线程去分别处理不同的事情 xff0c 看起来 xff0c 多线程处理并不比单线程循环处理的效率看起来那么的高 多进程是在利用我们电脑C
  • Python自带的GUI(Tkinter)教程

    1 Python Tkinter xff08 GUI图形界面 xff09 xff1a a What s Tkinter Tkinter 是什么 xff1f Tkinter是Python自带的一个GUI库 xff0c 他可以将我们在comma
  • Python科学计算包NumPy教程

    在我的Github上有一份代码与教程结合的jupyter Notebook文件 xff0c 大家可以clone下来看一看 下面会用实例的方式给出一些examples xff1a Tutorial教程 官方中文文档 span class to
  • 区块链入门的几个概念

    区块链入门的几个简单概念 1 What s Block Chain 区块链是一门软件技术 xff0c 从本质上来看就像是一个分布式的DataBase xff0c 是一个去中心化 xff0c 分布式技术 由于是分布式的 xff0c 所以区块链
  • Mysql GROUP_CONCAT与CONCAT_WS配合使用单选、多选拼接

    举例1 可以使用IF函数将单选和多选的值分别拼接 xff0c 并在最后的结果中使用CONCAT WS函数将它们合并 xff1a idcolors11223344 551 2 362 3 4 5 我们想要的结果为1 2 3 4 5 下面开始测
  • A Survey on Concept Drift Adaptation Note

    A Survey on Concept Drift Adaptation Abstract Concept drift primarily refers to an online supervised learning scenario w
  • Learning under Concept Drift:A Review

    Learning under Concept Drift A Review Abstract Concept drift describes unforeseeable changes in the underlying distribut
  • Note for Understanding Neural Networks Through Deep Visualization

    Note for Understanding Neural Networks Through Deep Visualization Abstract 近年来 xff0c 在训练大型深度神经网络方面取得了巨大进展 xff0c 其中包括训练卷积
  • ML-Leaks Note

    ML Leaks Model and Data IndependentMembership Inference Attacks and Defenses onMachine Learning Models xff08 机器学习模型上与模型和
  • C++中读取字符串的方式

    这里写自定义目录标题 C 43 43 读取字符串的两种方式1 getline 读取行的输入2 get 读取行的输入 C 43 43 读取字符串的两种方式 1 getline 读取行的输入 getline函数读取整行 xff0c 它使用通过回
  • 二叉树的基本操作

    二叉树 先序和中序确定二叉树 后序以及中序确定二叉树 span class token comment 指针版本 span span class token keyword struct span node span class token
  • 2023秋招面试准备

    2022 秋招资料 算法数据结构 螺旋矩阵问题 螺旋矩阵I 将 1 n m 个数按蛇形方向填入数组中 记录蛇形矩阵偏移量方法 xff0c 四个不同方向右下左上 xff0c 判断什么情况下矩阵遍历完 xff0c 1 要么出界 2 要么走完 s