回形打印二维数组,要求不在内存中开辟二维数组——腾讯二面

该题为腾讯mxg面试委员会二面试题,要求如下:
逐行打印n * n回型矩阵( 不可以在内存填好整个矩阵然后再打印)

n=3
1 2 3
8 9 4
7 6 5

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

 

不在内存中开辟二维数组,则应该寻找(i, j)与num的关系,达到O(1)计算(i, j)上应该填充的num

将二维数组看成一层一层的圈,如图。外层(红色)为第0圈,中间层(深蓝)为第1圈,内层(浅蓝)为第2层

以下均以n=6为例:

根据n的大小可计算(i, j)所处在第几个圈中,i_circle_index = Min(Min(i, j)-0, n-1-Max(i, j))

其实就是判断i, j中离0或n-1大小最小的那个就是当前圈,如(0, 3)->0,(1, 2)->1,(1, 5)->0,(2, 3)->2

 

根据n和(i, j)所处圈可计算当前圈中数字的个数i_circle_num = (n-1-(2*i_index))*4<=0?1:(n-1-(2*i_index))*4,这个比较好理解,就不做解释了

接下来就是求每个(i, j)所对应的值num了

我们将圈分为四个部分Top、Right、Bottom、Left,观察(i, j)可以发现,[Top、Right]中 i => j、[Bottom、Left]中i < j

我们规定[(0, 0)、...、(0, n-1)]为Top共有n-2*i_circle_index个数,[(1, n-1)、...、(n-1, n-1)]为Right共有n-2*i_circle_index-1个数,[(n-1, n-2)、...、(n-1, 0)]为Left共有n-2*i_circle_index-1个数,[(n-2)、...、(1)]为Left共有n-2*i_circle_index-2个数

 

ok其实计算到这里,很多东西都出来了,我们现在需要做的就是在输出每个(i, j)位置的时候,判断(i, j)属于第几个圈,之前的圈共有多少个数字,(i, j)在该圈中属于[Top、Right、Bottom、Left]的那个部分,在当前部分属于第几个元素,然后就能计算出当前位置(i, j)对应的值num了

num = 外层圈数字累加和+当前圈所处属性[op、Right、Bottom、Left]的数字个数+当前属性中的个数

 

#include <iostream>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <vector>

using namespace std;
int Min(int a, int b){
    return a>b?b:a;
}
int Max(int a, int b){
    return a>b?a:b;
}

//计算当前i,j所处第几个圈
int getCircleIndex(int i, int j, int n){
    return Min(Min(i, j)-0, n-1-Max(i, j));
}

//计算当前圈共有多少元素
int getCircleNum(int i_index, int n){
    if(i_index < 0){
        return 0;
    }else{
        return (n-1-(2*i_index))*4<=0?1:(n-1-(2*i_index))*4;
    }
}

//环形打印二维数组
void PrintClockWiseMatrix(int n){
    if(n <= 0){
        return;
    }
    int i_acc_circle_num[n+1];  //存储该圈的起始大小(前i圈数字的累加和)
    int i_circle = n/2;
    if(n%2){
        i_circle ++;
    }
    memset(i_acc_circle_num, 0, sizeof(i_acc_circle_num));
    i_acc_circle_num[0] = 0;    
    for(int i = 1 ;  i <= i_circle ; i ++){
        i_acc_circle_num[i] = i_acc_circle_num[i-1] + getCircleNum(i-1, n);
    }

    for(int i = 0 ; i < n ; i ++){
        for(int j = 0 ; j < n ; j ++){
            int i_circle_index = getCircleIndex(i, j, n);
            int i_circle_num = i_acc_circle_num[i_circle_index];
            int i_num = 0;
            if(i <= j){
                if(i == i_circle_index){
                    //top
                    i_num = i_circle_num + j - i_circle_index + 1;
                }else{
                    //right 
                    i_num = i_circle_num + i - i_circle_index + n-2*i_circle_index/*top元素个数*/;
                }
                printf("%2.2d ", i_num);
            }else{
                if(i == n-1-i_circle_index){
                    //bottom
                    i_num = i_circle_num + n-i_circle_index-1-j + 2*(n-2*i_circle_index)-1;
                }else{
                    //left
                    i_num = i_circle_num + n-i_circle_index-1-i + 3*(n-2*i_circle_index)-2;
                } 
                printf("%2.2d ", i_num);
            }
        }
        printf("\n");
    }

}

int main(){
    PrintClockWiseMatrix(10);
    return 0;
}

输出结果:

n=5

n=6

n=10

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值