2016美团校招真题:二维数组打印

题目

有一个二维数组(n*n),写程序实现从右上角到左下角沿主对角线方向打印。
给定一个二位数组arr及题目中的参数n,请返回结果数组。

测试样例:
[[1,2,3,4],[5,6,7,8],[9,10,11,12],[13,14,15,16]],4

返回:
[4,3,8,2,7,12,1,6,11,16,5,10,15,9,14,13]

解题

1. 解题思路A
  • 利用广搜思想(我也很想知道为什么我会想到广搜=。=)
  • 如下图所示,从右上角的4出发,先往左访问3,再往下访问8;然后从4的左儿子3出发,先往左访问2,再往下访问7;再从4的下儿子出发,往左访问7再往下访问12,以此类推(蓝色→橙色→绿色→红色→黄色…)
    arrayprint1

  • 那么就有一个问题,有可能会重复访问,例如上述的7在访问3的时候被加入队列,但在访问8的时候又一次被加入队列,显然是需要剪枝的。这里列一下整个队列的添加情况应该是这样的:

    [4, 3, 8, 2, 7, (7), 12, 1, 6, (6), 11, (11), 16, 5, (5), 10, (10), 15, (15), 9, (9), 14, (14), 13]

  • 可以看到可能会重复访问的点都在每一次加入儿子节点后的队列尾部,而剪枝后的队列顺序就是题目要求的打印顺序,所以只需要维护一个队列,每次从队列里pop一个元素就将其加入结果容器中,并在每次访问儿子节点时都要判断是否和队尾元素重复
  • 代码如下,占用内存5048k,运行时间232ms
class Printer {
public:
    vector<int> arrayPrint(vector<vector<int> > arr, int n) {
        queue<pair<int, int>> q;
        q.push({ 0, n-1 });
        vector<int> path;
        pair<int, int> back_node;
        while(!q.empty()){
            // 访问队列最后一个点的坐标
            back_node = { q.back().first, q.back().second };

            // 取出最先加入队列的坐标和值
            pair<int, int> node = q.front();
            q.pop();

            // 将当前访问点的值加入路径队列
            path.push_back(arr[node.first][node.second]);       
            // 将当前点左边的点加入队列
            if(node.second-1>=0){
                if(back_node.first!=node.first || back_node.second!=node.second-1){
                    q.push({ node.first, node.second-1 });
                }            

            }

            // 将当前点下边的点加入队列
            if(node.first+1<n){
                if(back_node.first!=node.first+1 || back_node.second!=node.second){
                    q.push({ node.first+1, node.second });
                }                     
            }
        }
        return path;
    }
};
2. 解题思路B
  • 提交答案通过后看了别人的解题思路=。=
  • 哇,为什么代码可以这么简洁,认真思考后,得出一个教训:不要急着解题,把题意认真思考过先,打印结果都没完整看过一遍就想当然以为是广搜了。
  • 实现别人的解题思路,代码如下,占用内存8196k,运行时间328ms(理解不能为什么内存占用比广搜还多?)
class Printer {
public:
    vector<int> arrayPrint_other(vector<vector<int> > arr, int n) {
        vector<int> result;
        int startX=0, startY=n-1;
        while(startX<n && startY<n){
            int i=startX, j=startY;
            while(i<n && j<n){
                result.push_back(arr[i][j]);
                i++;
                j++;
            }
            if(startY>0) startY--;
            else startX++;
        }
        return result;
    }
};
  • 其实思路很简单,如下图所示,以黄色覆盖的点为每一次访问的起点,按蓝色线顺序,先是y坐标依次减1,碰到边界后x坐标依次加1;然后对于每一个起点,坐标x和y都+1按橙色线顺序访问(代码里用i和j分别迭代),主要就是边界判断问题了=。=
    arrayprint2
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值