lc[数组]---59.螺旋矩阵②(new二维数组&&循环不变量&&模拟)

一、题目描述

 ​​​Day8:寻路算法---深度寻路__Brooke_的博客-CSDN博客

个人的原始解法:类似于上面的博客所解(就是比较费空间)下面着重介绍一下"循环不变量"

class Solution
{
public:
    typedef struct Pos { int x; int y; }Pos;//记录坐标
    enum dir { right = 0, down, left, up };
    bool Check(bool** Map, Pos CurPos, int CurDir, int n)//判断是否需要改变的方向的
    {
        if (CurDir == 0)//向右的
        {//检测右边是否为边界or已经走过的地方
            if (CurPos.x + 1 >= n || Map[CurPos.x + 1][CurPos.y] == 1)//短路特性
            {
                return true;//说明需要改变方向
            }
        }
        if (CurDir == 1)//向下的
        {//检测右边是否为边界or已经走过的地方
            if (CurPos.y + 1 >= n || Map[CurPos.x][CurPos.y + 1] == 1)//短路特性
            {
                return true;//说明需要改变方向
            }
        }
        if (CurDir == 2)//向左的
        {//检测右边是否为边界or已经走过的地方
            if (CurPos.x - 1 <0 || Map[CurPos.x - 1][CurPos.y] == 1)//短路特性
            {
                return true;//说明需要改变方向
            }
        }
        if (CurDir == 3)//向上的
        {//检测右边是否为边界or已经走过的地方
            if (CurPos.y - 1 <0 || Map[CurPos.x][CurPos.y - 1] == 1)//短路特性
            {
                return true;//说明需要改变方向
            }
        }
        return 0;
    }
    void move(int CurrentDir, Pos& CurrentPos)
    {
        if (CurrentDir == 0)//向右的
        {
            CurrentPos.x += 1;
        }
        if (CurrentDir == 1)//向下的
        {
            CurrentPos.y += 1;
        }
        if (CurrentDir == 2)//向左的
        {
            CurrentPos.x -= 1;
        }
        if (CurrentDir == 3)//向上的
        {
            CurrentPos.y -= 1;
        }
    }
    vector<vector<int>> generateMatrix(int n)
    {
        if(n!=1)
        {
        Pos CurrentPos = { 0,0 };//起始坐标
        //观察图像易知,行走的顺序始终都是按照这样的变化规律的
        //向左or向右的运动--仅仅只是改变横坐标,当向上or向下的时候--改变n(物理存储上)
        int CurrentDir = 0;//默认从向右走起
        int** res = new int* [n];//全部置为0,表示没有走过
        for (int i = 0; i < n; i++)
        {
            res[i] = new int[n] {0};//错误2
        }
        bool** FlagMap = new bool* [n];//全部置为0,表示没有走过
        for (int i = 0; i < n; i++)
        {
            FlagMap[i] = new bool[n]{0};//错误4
        }
        FlagMap[CurrentPos.x][CurrentPos.y] = 1;//起点先标记走过
        for (int i = 0; i < n * n; i++)//一共操作n²次
        {
            if (Check(FlagMap, CurrentPos, CurrentDir, n))
            {//看是否要改变方向
                CurrentDir = (CurrentDir + 1) % 4;//不能超过4
            }
            //放入对应位置的数组
            res[CurrentPos.x][CurrentPos.y] = (i+1);//错误5:前后两者的顺序
            //走到下一个要插入的位置
            move(CurrentDir, CurrentPos);
            //flagmap对应位置需要标记走过
            FlagMap[CurrentPos.x][CurrentPos.y] = 1;
        }
        vector<vector<int>> Res;
        for (int i = 0; i < n; i++)
        {
            vector<int>tmp;
            Res.push_back(tmp);//错误三
            for (int j = 0; j < n; j++)
            {
                Res[i].push_back(res[j][i]);
            }
        }
        for (int i = 0; i < n; i++)
        {
            delete[]  res[i];
        }
        delete[]res;
        for (int i = 0; i < n; i++)
        {
            delete[]FlagMap[i];
        }
        delete[]FlagMap;
        return Res;
        }
        else
        {
            vector<vector<int>> res;
            vector<int> vec;
            vec.push_back(1);
            res.push_back(vec);
            return res;
        }
        vector<vector<int>> res;
        return res;
    }
};

注意:

        ①用new来申请二维数组的时候,在对每一行开辟内存的时候,一定要记得切换。res[i]

        ②vector<vector<int>> res只是声明有这样一个类型,在做具体int类型数据的插入的时候,一定要先插入一个vector<int>进去

        ③报错 :.Runtime error: load of value 127, which is not a valid value for type 'bool'

 原因:在开辟bool类型的二维数组的时候,并没有给其初始化,导致此error

     

二、循环不变量解法

螺旋矩阵

 

        这里每一种颜色,代表一条边,我们遍历的长度,可以看出每一个拐角处的处理规则,拐角处让给新的一条边来继续画。

        这也是坚持了每条边左闭右开的原则。

        一些同学做这道题目之所以一直写不好,代码越写越乱。就是因为在画每一条边的时候,一会左开右闭,一会左闭右闭,一会又来左闭右开,岂能不乱。

        代码如下,已经详细注释了每一步的目的,可以看出while循环里判断的情况是很多的,代码里处理的原则也是统一的左闭右开。

class Solution {
public:
    vector<vector<int>> generateMatrix(int n) {
        vector<vector<int>> res(n, vector<int>(n, 0)); // 使用vector定义一个二维数组
        int startx = 0, starty = 0; // 定义每循环一个圈的起始位置
        int loop = n / 2; // 每个圈循环几次,例如n为奇数3,那么loop = 1 只是循环一圈,矩阵中间的值需要单独处理
        int mid = n / 2; // 矩阵中间的位置,例如:n为3, 中间的位置就是(1,1),n为5,中间位置为(2, 2)
        int count = 1; // 用来给矩阵中每一个空格赋值
        int offset = 1; // 需要控制每一条边遍历的长度,每次循环右边界收缩一位
        int i,j;
        while (loop --) {
            i = startx;
            j = starty;

            // 下面开始的四个for就是模拟转了一圈
            // 模拟填充上行从左到右(左闭右开)
            for (j = starty; j < n - offset; j++) {
                res[startx][j] = count++;
            }
            // 模拟填充右列从上到下(左闭右开)
            for (i = startx; i < n - offset; i++) {
                res[i][j] = count++;
            }
            // 模拟填充下行从右到左(左闭右开)
            for (; j > starty; j--) {
                res[i][j] = count++;
            }
            // 模拟填充左列从下到上(左闭右开)
            for (; i > startx; i--) {
                res[i][j] = count++;
            }

            // 第二圈开始的时候,起始位置要各自加1, 例如:第一圈起始位置是(0, 0),第二圈起始位置是(1, 1)
            startx++;
            starty++;

            // offset 控制每一圈里每一条边遍历的长度
            offset += 1;
        }

        // 如果n为奇数的话,需要单独给矩阵最中间的位置赋值
        if (n % 2) {
            res[mid][mid] = count;
        }
        return res;
    }
};

注意:

        ①循环圈数是n/2,如果是奇数,会留下最后一个mid点,判断一下赋值即可

        ②offset控制每次均为左闭右开

其他解法:

class Solution {
public:
    vector<vector<int>> generateMatrix(int n) {
        int t = 0;      // top
        int b = n-1;    // bottom
        int l = 0;      // left
        int r = n-1;    // right
        vector<vector<int>> ans(n,vector<int>(n));
        int k=1;
        while(k<=n*n){
            for(int i=l;i<=r;++i,++k) ans[t][i] = k;
            ++t;
            for(int i=t;i<=b;++i,++k) ans[i][r] = k;
            --r;
            for(int i=r;i>=l;--i,++k) ans[b][i] = k;
            --b;
            for(int i=b;i>=t;--i,++k) ans[i][l] = k;
            ++l;
        }
        return ans;
    }
};

类似题目

  • 54.螺旋矩阵
  • 剑指Offer 29.顺时针打印矩阵
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

_Ocean__

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值