PREV-2 打印十字图(Java)两种解法(递归and分治)

吐槽一下,官方给出的图我真的是看不出十字,更找不到任何规律.还有就是真的太久没刷题,思维就跟不上了,太菜了.
题目要求就不写了,直接上一张能看明白的图吧
在这里插入图片描述这才叫十字啊(抠鼻)

题解1(递归解法)

这个大十字可以看成是一个个的红圈儿和中间的那个十字组成的,只要在一个二维数组中画出了最外层的红圈,就能用相同的方法,画出所有的红圈,再加上中间的十字,这个题就OK了,递归的过程就是在二维数组中从外向里画红圈.画一个红圈又分成了几步,上(第一,二,三行),下(倒数第一,二,三行),左(左边第一列),右(右边第一列)

代码

import java.util.Scanner;
 
public class PREV_2 {
	static int count;//递归次数
	static char[][] ch;//二维数组
	public static void main(String[] args) {
		Scanner sc=new Scanner(System.in);
		int n=sc.nextInt();
		int num=5+4*n;//二维数组的总行数,总列数
		count=n;
		ch=new char[num][num];
		for(int i=0;i<num;i++){
			for(int j=0;j<num;j++){
				ch[i][j]='.';
			}
		}
		mid();
		surrounded(0,num,0);
		print();
	}
	//画外层的大十字
	public static void surrounded(int head ,int num,int temp){//temp为当前递归次数,
		if(temp>=count)return;//如果递归次数够了,就退出
		//画第一行,倒数第一行
		for(int i=head+2;i<num-2;i++){
			ch[head][i]='$';
			ch[num-1][i]='$';
		}
		//画第二行,倒数第二行
		ch[head+1][head+2]='$';
		ch[head+1][num-3]='$';
		ch[num-2][head+2]='$';
		ch[num-2][num-3]='$';
		//画第三行,倒数第三行
		int temp1=0;//用于循环时打印'$'
		for(int i=head;i<head+3;i++){
			//第三行
			ch[head+2][i]='$';//左边
			ch[head+2][num-1-temp1]='$';//右边
			//倒数第三行
			ch[num-3][i]='$';//左边
			ch[num-3][num-1-temp1]='$';//右边
			temp1++;
		}
		//画左右两边
		for(int i=head+2;i<num-2;i++){
			ch[i][head]='$';//左边
			ch[i][num-1]='$';//右边
		}
		temp++;
		surrounded(head+2,num-2,temp);//递归调用
	}
	//画中间的十字
	public static void mid(){
		int midline=ch.length/2;
		int j=count*2;
		for(int i=0;i<5;i++){
			ch[midline][j+i]='$';
			ch[j+i][midline]='$';
		}
	}//打印图形
	public static void print(){
		for(int i=0;i<ch.length;i++){
			for(int j=0;j<ch.length;j++){
				System.out.print(ch[i][j]);
			}
			System.out.println();
		}
	}
}

题解2(分治解法)

那个大十字可以看出是由4部分组成,左上,右上,左下,右下,而且四部分是相同的,只是存在镜像关系,只要能得到任意一部分,就能得到4部分,以输入1的十字图,左上部分为例,先确定四个点(四个白格),再确定每一层,具体见代码
在这里插入图片描述

代码

import java.util.Scanner;

public class PREV_2{
	public static void main(String args[]){
		Scanner scanner=new Scanner(System.in);
		int n=scanner.nextInt();
		int num=4*n+5;//需要打印的总行数,总列数
		char [][]c=new char[num][num];//最终的二维数组
		int [][]c1=new int[(num/2)+1][(num/2)+1];//左上部分的数字数组便于判断
		char [][]m=new char[(num/2)+1][(num/2)+1];//左上部分的二维数组
		for(int i=0;i<num;i++){
			for(int j=0;j<num;j++){
				c[i][j]='.';//设置初始值
			}
		}
		for(int i=0;i<c1.length;i++){
			for(int j=0;j<c1.length;j++){
				c1[i][j]=30;//设置初始值为30,因为该题最多有29层,也可以是任意一个数,最好与本题无关的一个数
			}
		}
		c1[0][0]=0;//将4个点设置为0,便于区分
		c1[0][1]=0;
		c1[1][0]=0;
		c1[1][1]=0;
		for(int k=0;k<n*2;k++){//大的循环次数
		for(int i=0;i<c1.length;i++){
			for(int j=0;j<c1.length;j++){
				if(c1[i][j]==30){//即就是从未扫描到的,因为扫描到了的会被重新赋值
					if((i==0||j==0)||c1[i-1][j-1]==k){//看图, 如果在边缘,或者斜上角是上一层赋的值,那么这个应该赋值
					c1[i][j]=k+1;//为什么每一轮的值要不一样,如果一样的话,会影响到下一层判断
					}
				}
			}
		}
		}
		//数字数组转成'.'$'数组
		for(int i=0;i<c1.length;i++){
			for(int j=0;j<c1.length;j++){
				if(c1[i][j]%2==0){//偶数对应的是'.',奇数对应的是'$'
					m[i][j]='.';
				}else{
					m[i][j]='$';
				}
			}
		}
		//组成总二维数组,需要找到每一块和左上数组的数学关系.
		 for(int i=0;i<5+(n-1)*2;i++){
			 for(int j=0;j<5+(n-1)*2;j++){
				 c[i][j]=m[i][j];//左上
				 c[i][j+5+(n-1)*2-1]=m[i][5+(n-1)*2-1-j];//右上
				 c[5+(n-1)*2-1+i][j]=m[5+(n-1)*2-1-i][j];//左下
				 c[5+(n-1)*2-1+i][5+(n-1)*2-1+j]=m[5+(n-1)*2-1-i][5+(n-1)*2-1-j];//右下
			 }
		 }
		 for(int i=0;i<c.length;i++){
			 for(int j=0;j<c.length;j++){
				 System.out.print(c[i][j]);
			 }
			 System.out.println();
		 }
	}
}

总结:还是得每天练练题,保持手感,不然思维真的会退化.对了,打个广告,这是我的个人网站哦,点我点我有想练练手的小伙伴,可以评论,我告诉你github上的链接哦.

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值