【算法】打印算法题总结

前言

本文记录了我对打印算法题的总结。先说说什么事打印算法题,就是按照一定的规则打印二维矩阵。例如:旋转正方形矩阵:

1 2 3 4                             13 9 5 1
5 6 7 8              --->           14 10 6 2
9 10 11 12                          15 11 7 3
13 14 15 16                         16 12 8 4

接下来,将会有几道打印算法题,先看看各个题目的解法,再来总结一下解题方法

例子

1、旋转正方形矩阵

题目

给定一个整型正方形矩阵matrix,请把该矩阵调整成 顺时针旋转90度的样子。
【要求】 额外空间复杂度为O(1)。
例如:
1 2 3 4
5 6 7 8
9 10 11 12
13 14 15 16
=========
13 9 5 1
14 10 6 2
15 11 7 3
16 12 8 4
【要求】 额外空间复杂度为O(1)

思路:

给定左上角(lx, ly)和右下角(rx, ry)的坐标,确定一个矩阵。对这个矩阵作以下操作:
第一轮,先旋转最外面的矩阵
1,4,16,13作为1组
2,8,15,9作为1组
3,12,14,5作为1组
把以上分组依次交换位置
左上角右下角往中心移动,重复上面的交换步骤,直至lx >= lx

算法实现

public static void rotateMatrix(int[][] matrix){
    int lx = 0;
    int ly = 0;
    int rx = matrix.length - 1;
    int ry = matrix[0].length - 1;
    while(lx < rx) {
      rotateEdage(matrix, lx++, ly++, rx--, ry--);
    }
  }

  public static void rotateEdage(int[][] matrix, int lx, int ly, int rx, int ry) {
    // 计算需要交换的次数
    int times = rx - lx;
    int i = 0;
    int tmp = 0;
    while(i != times) {
      int p4 = matrix[rx - i][ly];
      tmp = matrix[lx][ly + i];
      matrix[lx][ly + i] = matrix[rx - i][ly];
      matrix[rx - i][ly] = matrix[rx][ry - i];
      matrix[rx][ry - i] = matrix[lx + i][ry];
      matrix[lx + i][ry] = tmp;
      i++;
    }
  }

2、转圈打印矩阵

题目

给定一个整型矩阵matrix,请按照转圈的方式打印它。
例如:1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
打印结果为:1,2,3,4,8,12,16,15,14,13,9, 5,6,7,11, 10
【要求】 额外空间复杂度为O(1)。

图解:


转圈打印

思路

设计一个函数,函数功能是给一个左上角和右下角的坐标,打印由这两个点确认的矩形上的点。
然后从原始矩阵的左上角(lx, ly)和右下角(rx, ry)开始打印,打印一圈后,左上角和右下角均往中心移动,即lx++,ly++,rx--, ry--,直至到左 >= 右

算法实现

  /// 转圈打印矩阵
  public static void printMatrixSpiralOrder(int[][] matrix) {
    int lx = 0;
    int ly = 0;
    int rx = matrix.length - 1;
    int ry = matrix[0].length - 1;
    // 每打印一趟,左上角和右下角都往中心移动一格
    while(lx <= rx && ly <= ry) {
      printEdage(matrix, lx++, ly++, rx--, ry--);
    }
  }

  /// 传递左上角(lx, ly),右下角(rx, ry)
  /// 打印这个矩阵所有的数
  public static void printEdage(int[][] matrix, int lx, int ly, int rx, int ry) {
    if(lx == rx) {
      // 同行,只移动列
      for(int i = ly; i <= ry; i++) {
        System.out.print(matrix[lx][i]);
      }
    }else if(ly == ry) {
      // 同列,只移动行
      for(int i = lx; i <= rx; i++) {
        System.out.print(matrix[i][ly]);
      }
    }else {
      // 不同行,不同列
      int x = lx;
      int y = ly;
      // 打印top
      while(y != ry) {
        System.out.print(matrix[x][y] + " ");
        y++;
      }
      // 打印left
      while(x != rx) {
        System.out.print(matrix[x][y] + " ");
        x++;
      }
      // 打印bottom
      while(y != ly) {
        System.out.print(matrix[x][y] + " ");
        y--;
      }
      // 打印right
      while(x != lx) {
        System.out.print(matrix[x][y] + " ");
        x--;
      }
    }
  }

3、"之"字形打印矩阵

题目

给定一个矩阵matrix,按照“之”字形的方式打印这个阵,
例如:1 2 3 4 5 6 7 89 10 11 12 “之”字形打印的结果为:
1,2,5,9,6,3,4,7,10,11, 8,12
【要求】 额外空间复杂度为O(1)。

图解:


之形打印

思路

同样地,先设计一个函数,作用是给定左下角(lx, ly)和右上角(rx, ry),打印这条直线上的点
首先取(0, 0)作为公共出发点,打印完毕后:
(lx, ly)向下移动,直至到达底部后,ly向右移动
(rx, ry)向右移动,直至到达右边界后,rx向下移动
重复上述过程,直到左下角(lx, ly)和右上角(rx, ry)相遇

算法实现

public static void zhiPrintMatrix(int[][] matrix) {
    int lx =  0;
    int ly = 0;
    int rx = 0;
    int ry = 0;
    int maxX = matrix.length - 1;
    int maxY = matrix[0].length - 1;
    boolean isReverse = true;
    while(ly != maxY + 1) {
        printLine(matrix, lx, ly, rx, ry, isReverse);
        isReverse = !isReverse;
        // 只有lx到达底部时,ly才移动
        ly = lx == maxX ? ly + 1 : ly;
        // 先将lx移动到底部
        lx = lx == maxX ? lx : lx + 1;
        // 只有ry到达右边界时,rx才向下移动
        rx = ry == maxY ? rx + 1 : rx;
        // 先将ry移动到右边界
        ry = ry == maxY ? ry : ry + 1;
    }
  }

  public static void printLine(int[][] matrix, int lx, int ly, int rx, int ry, boolean isReverse) {
    if(isReverse) {
      // 从左下打印到右上
      int x = lx;
      int y = ly;
      do {
        System.out.print(matrix[x][y] + " ");
        x--;
        y++;
      }while(x >= rx && y <= ry);
    }else {
      // 从右上打印到左下
      int x = rx;
      int y = ry;
      do {
        System.out.print(matrix[x][y] + " ");
        x++;
        y--;
      }while(x <= lx && y >= ly);
    }
  }

总结

通过以上三道题,我们可以总结出以下观点

1、宏观的角度

我们都是从宏观的角度去思考的,而不是想着发掘每一个点(x,y)和(x', y')的关系转换。我们需要在宏观和微观之间平衡,逐步的解剖问题。例如在第一二道题,我们都是通过解决外矩阵后,再解决内矩阵的方式解决问题的。

2、设计一个子模块打印函数

例如给定左上角和右上角打印一个矩阵等打印函数,记住一些常用的打印函数,可以让我们更快地解决问题

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

推荐阅读更多精彩内容

  • 1. 有一棵二叉树,请设计一个算法,按照层次打印这棵二叉树。 给定二叉树的根结点root,请返回打印结果,结果按照...
    Crystalajj阅读 3,979评论 0 2
  • 变换(Transformations) 我们可以尝试着在每一帧改变物体的顶点并且重设缓冲区从而使他们移动,但这太繁...
    IceMJ阅读 4,132评论 0 1
  • error for object 0x112bca4f0: pointer being freed was not...
    杨大虾阅读 359评论 0 0
  • 今天玩得很开心,不过得出的结论是:我更偏爱一个人安静 我会越来越好的。加油。
    一天到晚吟唱的鱼阅读 195评论 0 0
  • 生活处处离不开表达,有人啰里啰嗦让人搞不清说了什么,有人说什么别人都不当回事,还有人像大师一样一呼百应。关键在哪儿...
    海星_love阅读 136评论 0 1