笔试时遇到一个笔试题,
直接上代码
public class Main{
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int n = sc.nextInt();
int size = 1;
//获得矩阵边长
for(int i = 0; i < n; i++){
size *= 2;
}
//逐位输出
for(int i = 1; i<=size; i++){
for(int j = 1; j<=size; j++){
System.out.print(writeCount(n,i,j)+" ");
}
System.out.println();
}
}
//传入矩阵的阶次与横纵位置
public static int writeCount(int n, int width, int height){
int size = 1;
//获取矩阵的边长
for(int i = 0; i < n; i++){
size *= 2;
}
//矩阵左上角为全0矩阵
if((width <= size/2) && (height <= size/2)){
return 0;
}
if(n == 1){
//递归至1阶时判断数值
if(width <= 1 && height <= 1){
return 0;
}else{
return 1;
}
}else{
//高阶时进行退阶
if(width - size/2 > 0){
width -= size/2;
}
if(height - size/2 > 0){
height -= size/2;
}
//返回下一阶阶数与新的横纵位置
return writeCount(n-1, width, height);
}
}
}
解题的关键就在于“退阶”的实现,我们可以先用“进阶”的思路来手写一下A1->A2,A2->A3的位置变化:
A1->A2:我们先取到A1左上角的“0”,记录位置(1,1),这个“0”在A2中共出现了三次,位置分别是(1,3)(3,1)(3,3)。
A2->A3:同样的A2中的三个“0”又各出现了三次,如(1,3)在A3中出现的位置是(1,7)(5,3)(5,7)
如果这样还不好发现规律的话,我们可以试着把左上角填充的全零矩阵也改为An-1,那么A1->A2过程中的(1,1)就会变为(1,1)(1,3)(3,1)(3,3),A2->A3过程中的(1,3)就会变成(1,3)(1,7)(5,3)(5,7)。
通过简单的找规律就会发现An->An+1过程中的(a,b)就会变成**(a,b)(a,b+2^n)(a+2 ^n,b)(a+2 ^n,b+2 ^n)且a,b<=2 ^n**。
当然如果有矩阵的相关知识可以更快得出这个结果,并不用举例子这种土办法。
那么相应的退阶操作就是根据传入的坐标(a,b)找到大于2^(n-1)的值将其变为下一阶的位置,依次递归知道已知的A1。
介于n取值范围为[2 ^ 2 ,2^ 10] ,即使时间复杂度为O(n^2)也不会造成太大的时间占用,所以这个代码也只是一个雏形,仅代表个人拙见。