蓝桥杯学习之回形取数Java

这是对蓝桥杯上例题代码的学习理解和注解

例题代码给了3个语言的代码

C++ Java Python

我学习了前两个语言的代码并全部用Java重写并注解了一遍

C++的代码要比Java的更加清晰,但是行数要比Java更多

先上用Java重写后的C++版本

public static void function1()
    {
        Scanner in=new Scanner(System.in);
        int m,n;
        m=in.nextInt();//行
        n=in.nextInt();//列
        int[][] a=new int[m+1][n+1];
        int[][] vis=new int[m+1][n+1];
        for(int i=1;i<=m;i++)
        {
            for(int j=1;j<=n;j++)
            {
                a[i][j]=in.nextInt();
            }
        }
        int x=1;
        int y=1;
        System.out.print(a[x][y]);//先把输出起点的位置 后面的操作都是先走路再输出 所以必须先把起点输出
        vis[1][1]=1;//标记起点
        int sum=1;//可走总步数=总数字个数-1(起点)
        while(sum<n*m)//一次循环走完一个圈子 越走越小
        {
            //先往下
            while(x+1<=m && vis[x+1][y]==0)//若下一个没越界且没有走过
            {
                x++;//往下走
                System.out.print(" "+a[x][y]);//输出该点的数字f
                vis[x][y]=1;//标记为已走过
                sum++;//可走的步数-1
            }
            //再往右
            while(y+1<=n && vis[x][y+1]==0)
            {
                y++;
                System.out.print(" "+a[x][y]);
                vis[x][y]=1;
                sum++;
            }
            //再往上
            while(x-1>=1 && vis[x-1][y]==0)
            {
                x--;
                System.out.print(" "+a[x][y]);
                vis[x][y]=1;
                sum++;
            }
            //再往左
            while(y-1>=1 && vis[x][y-1]==0)
            {
                y--;
                System.out.print(" "+a[x][y]);
                vis[x][y]=1;
                sum++;
            }
        }
    }

大致思路就是:

以(1,1)为起点作为整个数表的起点

因此数组列和行要比输入的多1

核心思路:0.计算好要移动的总步数->1.获取下一个格子->2.判断是否符合满足条件->3.移动到4.这个格子并输出内容->5.将此格子标记为已走过->6.步数-1->重复1

从起点开始走

我们就可以先把起点格子中的数输出

然后在进行上述核心思路的方法

这里注意是先判断再移动再输出,顺序不能搞乱了

即可得到答案

 Java的例题代码与C++的代码核心思路大体一致 唯一的区别就是对起点的处理

以及在处理移动时的手段不同

Java版本

public static void function2()
    {
        Scanner in=new Scanner(System.in);
        int m,n;
        m=in.nextInt();//行
        n=in.nextInt();//列
        int[][] a=new int[m][n];
        for(int i=0;i<m;i++)
        {
            for(int j=0;j<n;j++)
            {
                a[i][j]=in.nextInt();
            }
        }
        int[][] dir=new int[][]{{1,0},//往下 d=0
                               {0,1},//往右 d=1
                               {-1,0},//往上 d=2
                               {0,-1}};//往上 d=3
        //初始坐标 起点上方
        int x=-1;
        int y=0;
        int sum=0;//总步数
        int d=0;//控股之方向 d=
        while(sum<n*m)
        {
            sum++;//步数-1
            //获取下一个格子的坐标
            int nx=x+dir[d][0];
            int ny=y+dir[d][1];
            if(nx<0 || ny <0 || nx>=m || ny>=n || a[nx][ny]==-1)//判断 下一个格子 是否超过上界 下界 左界 右界 是否重复
            {
                //如果越界或重复走过
                    /*0->1 d=d+1=0+1=1%4=1;
                    1->2  d=d+1=1+1=2%4=2;
                    2->3 d=d+1=2+1=3%4=3;
                    3->0 d=d+1=3+1=4%4=0
                    * */
                d=(d+1)%4;//转向
                //获取下个格子的坐标
                nx=x+dir[d][0];
                ny=y+dir[d][1];
                //下一个格子可以走 移动到下一个格子
                x=nx;
                y=ny;

            }else{
                //下一个格子可以走 移动到下一个格子
                x=nx;
                y=ny;
            }
            System.out.print(a[x][y]+" ");//将格子输出
            a[x][y]=-1;//标记已走过
        }

    }

核心思路仍和C++的一样:

 0.计算好要移动的总步数->1.获取下一个格子->2.判断是否符合满足条件->3.移动到4.这个格子并输出内容->5.将此格子标记为已走过->6.步数-1->重复1

步数的减少我认为先进行和后进行应该是没有区别的

与C++版本不同的是

Java版本的例题代码使用了一个二维数组dir[][]来控制移动

首先他仍旧是先获取下一个格子的坐标

这里获取格子坐标的时候用的是当前坐标+dir的偏移来得到的

dir则是通过变量d来控制方向->dir[d][0]或者dir[d][1]

回形取数的每一圈是下(x++)->左(y++)->上(x--)->右(y--)

因此dir({1,0},{0,1},{-1,0},{0,-1}}分别代表了

(x++,y不变)

(x不变,y++)

(x--,y不变)

(x不变,y--)

如果判断发现越界或者已走过

通过改变d的值来转换方向

这里d的值变化是1->2->3->0

因此用了(d+1)%4

之后便是获取下个格子-输出-标记-重复

如果判断没有越界和未走过

则就执行else的正常流程

下个格子-输出-标记-重复

这里标记是对原数表中的值直接修改为-1

与C++版本的单独列一个数组并不同

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值