小马的力扣日记Day4 数组 #59 螺旋矩阵II #189 轮转数组

#59 螺旋矩阵II


思路

要求从外到内安排进这n*n个数,我首先想到的是迷宫算法。

我想先设置一个大小n*n的布尔型二维数组,将其作为迷宫壁,初始化将整个数组先置为false,代表此路不通,然后将n*n的范围置为true,代表可走。

按照“右下左上”的顺序来走,当判断到一个方向可走,沿途将下一个数填入下一个格子,并将其布尔数组置为false,走到墙壁为止。

但是随着轮数的增加,每次判断的边界条件也会发生变化,再加上C++下标的问题,使得这个想法实现起来比较困难。

于是我用纸(随手抓了几张卫生纸)手动运作了一下填数的过程。

我把一次“右下左上”这套动作看作一个round,那么n=1和2的时候round=1 ,n=3和4的时候round=2,也就是n/2之后向上取整,即round=int(n/2)+(n mod 2)。

通过对每一个round行进下标的变化总结,可以得到round=r的时候的下标范式。(图上应该是round r 而不是round n 笔误)


代码

class Solution {

public:

    vector<vector<int>> generateMatrix(int n) {

        vector<vector<int>> res(n, vector<int>(n, 0)); 

        int round=(int (n/2)+n%2);

        int count,r,i,j=0;

        count=0;

        for (r=1; r<=round ; r++)

        {

            for (j=r-1; j<=n-r ; j++ )

            {

                count++;

                res[r-1][j]=count;

            }

            for (i=r; i<=n-r ; i++ )

            {

                count++;

                res[i][n-r]=count;

            }

            for (j=n-r-1; j>=r-1 ; j-- )

            {

                count++;

                res[n-r][j]=count;

            }

            for (i=n-r-1; i>=r ; i-- )

            {

                count++;

                res[i][r-1]=count;

            }

        }


        return res;

    }

};

反思


其实这个题主要是思考的时间比较久,实现起来倒是挺快的,也没怎么卡BUG。

实际情况中出过两个问题

第一个是vector的向量我不会声明,网上找了一个抄来的。

第二个问题是从右往左走和从下往上走这两个动作是i--和j--,我下意识写成了j++,报错之后才发现的。






#189 轮转数组



思路

这个题的思路比较多。

首先最暴力的解法,就是额外搞一个空数组,先把K及以后的元素依次放入,再将原数组第一个到第K-1个元素放入新数组,这样这个新数组就是所求的数组。

不过上述方法对空间非常浪费,所以我想到第二种方法,作为第一种方法的空间优化版本。就是用一个栈去做这个事情。不用申请一个新的数组,就只使用一个栈,将第K个及之后的元素入栈,然后将原数组的元素,往右移动K位,再将栈内元素出栈,组成数组的前面K个元素,就得到所求数组。这样做的好处就是,在大部分情况下,栈对空间的消耗是小于一个固定的大数组的,这就减少了空间消耗。

写到这里,自然而然地就能想到一种新的方法,就是将K位轮转拆分为K个单次轮转,每个单次轮转都将数组最后一个元素存下来,然后将其他数往右移动一位,最后将保存的元素放回数组第一位,这也就是题目进阶要求中想让我们达到的原地轮转,而不是单独开辟数组或者栈,代码实现的也是这种思路。(实际上这种方法超时了,虽然是n平方的时间复杂度,但是题目数据量太大了)

最后调整了思路,主要是看到有人用reverse这个翻转函数,那么这个题就进入到一个全新的思路里了。

我将移位过程看作两个包团的位置互换,如图k=3的时候,实际上我们要的结果就是,左边四个数组成的包团和右边三个数组成的包团之间的互换。

移位其实就是包团的互换

C++里并没有包团移位这个操作,但可以通过Reverse函数来实现。

如图Reverse就是将目标段落的数据翻转过来。

那么两个包团之间的互换,可以通过三次Reverse翻转来实现:

第一次翻转,翻转整个数组,这样左右两个包团的位置就实现了互换,尽管每个包团内部的顺序反了,但没关系,我们接下来就来把包团内部的顺序翻回来。

第二次翻转,翻转左包团内部,这样左包团内部实际上经历了两次翻转,内部的顺序恢复了正常。

第三次翻转,翻转右包团内部,同样的,右包团内部也经历了两次翻转,属于是顺序翻反了又翻回来。

这样就完成了整个操作。

各个包团内部翻转两次

代码

class Solution {

public:

    void rotate(vector<int>& nums, int k) {

        int i,j,temp=0;

        int numsize=nums.size()-1;

        k=k%nums.size();

        if (k!=0)

        {

            reverse (nums.begin(),nums.end());

            reverse (nums.begin(),nums.begin()+k);

            reverse(nums.begin()+k,nums.end());

        }

    }

};


反思


一开始很快就做出来了,我的代码长这样,大部分情况是没问题的。但是提交的时候就发现第34组测试样例就是特别大的一个样本,就很恶心,我超时了,我心想我n平方的时间复杂度都能超时???????

class Solution {

public:

    void rotate(vector<int>& nums, int k) {

        int i,j,temp=0;

        if (k!=0)

        {

        for (i=1;i<k+1; i++)

        {

            temp=nums[nums.size()-1];

            for (j=nums.size()-2 ; j>=0; j--)

            {

                nums[j+1]=nums[j];

            }

            nums[0]=temp;

        }

        }

    }

};

后来万佬告诉我,10^5的数据量意味着几乎只有时间复杂度不高于nlogn的算法能通过,10^6的话就几乎只能用n的算法,这是个不成文的经验,我还是太年轻了。

最后用翻转包团的方法解决了问题,其实我觉得这个题可以提炼出一种通用的方法。

即:当我们需要将数组的两个相邻子数组进行位置交换时,我们可以通过使用三次reverse操作来实现。


我又在想,这个包团交换的方法,能不能推广到非相邻的子数组呢,答案是肯定的。

如图,交换两个不相邻的包团,实际上我们可以看做是三个包团,交换不相邻的两个包团,而中间的包团的对外顺序不变,内部顺序也不变。


也就是说我们需要四次Reverse:

第一次,翻转整个数组,这样左右包团的相对顺序交换,而中间包团的对外位置不变。

然后我们分别对三个包团进行单独翻转,将它们的内部顺序改回来,就完成了不相邻子数组的位置交换。

即:当我们需要将数组的两个子数组进行位置交换时,我们可以通过使用三或四次reverse操作来实现。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 199,175评论 5 466
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 83,674评论 2 376
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 146,151评论 0 328
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 53,597评论 1 269
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 62,505评论 5 359
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 47,969评论 1 275
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,455评论 3 390
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,118评论 0 254
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,227评论 1 294
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,213评论 2 317
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,214评论 1 328
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,928评论 3 316
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,512评论 3 302
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,616评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,848评论 1 255
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,228评论 2 344
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 41,772评论 2 339

推荐阅读更多精彩内容