剑指offer:顺时针打印矩

剑指offer:顺时针打印矩阵

  • 题目JZ17:顺时针打印矩阵
  • 题目描述:输入一个矩阵,按照从外向里以顺时针的顺序依次打印出每一个数字,例如,如果输入如下4 X 4矩阵: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 则依次打印出数字1,2,3,4,8,12,16,15,14,13,9,5,6,7,11,10.
    在这里插入图片描述

算法

蚂蚁对象

  • 蚂蚁有三个向量:position,direction,next_position。分别表示了蚂蚁当前位置,蚂蚁方向,蚂蚁下一个位置。 这三个向量的关系是蚂蚁根据选择的方向,确定下一个位置。然后,下一位置决定了当前位置的更新情况。

蚂蚁爬地图的策略

  • 蚂蚁策略是:蚂蚁按照【右->下->左->上】的顺序来确定自己的方向。蚂蚁在移动过程中,会根据自己当前方向,来确定下一位置。然后可以根据下一位置是否是墙来选择是否更新当前位置和当前方向,这里的策略是:如果下一位置是墙,那么不更新当前位置,应该更新当前方向;如果下一位置不是墙,要进行的操作是:不更新当前方向,应该将当前位置的值进入容器,然后标记当前位置的值,最后更新当前位置。最后蚂蚁爬地图结束的策略是:当蚂蚁当前位置四周都是墙的时候就结束了。
  • 这里通过核心代码分析一下上述过程。
    首先介绍一下代码中的一些函数和数据结构:
    ①函数:find_direction(),会根据蚂蚁某个确定的方向搜索下一个位置是否碰到墙,如果碰到墙会返回 2,反之返回 1;environment()函数会检查蚂蚁四周是否都是墙,如果四周都是墙会返回 ture,反之返回false;
    ②数据结构:directions矩阵,directions保存了【右->下->左->上】四个方向向量;map保存了蚂蚁需要爬的地图;arr是一个记录蚂蚁经过路径的ArrayList容器;ants是一只蚂蚁。
  • 了解了相关函数后,就可以介绍下面代码了。
    首先通过一个外层while循环,让蚂蚁需要更新方向的时候,应该按照【右->下->左->上】的策略来循环更新方向。
    蚂蚁先在for循环中选择一个方向,
    然后进入内层while循环中,执行find_direction()函数,根据所选择的方向来确定是否在这个方向上继续搜索。
    然后find_direction()函数的返回值不满足条件时,也就是不再该方向搜索会跳出内层while循环,从而for循环迭代下一个方向。
    当四个方向都选择完毕,跳出for循环,准备来第二次的时候,此时应该通过environment()函数检查是否周围都是墙,以判断蚂蚁是否再爬一圈。
  • 在这里插入图片描述

代码:

import java.util.*;

class Ants{
    //方向常量 
    public static final int [] RIGHT = {1, 0, 0, 0};
    public static final int [] DOWN = {0, -1, 0, 0};
    public static final int [] LEFT = {0, 0, -1, 0};
    public static final int [] UP = {0, 0, 0, 1};
	
    private int [] position;
    private int [] direction;
    private int [] next_position;
    
    public Ants(int [] position, int [] direction) {
	this.position = position;
	this.next_position = position.clone();
	this.direction = direction;
    }
    
    
    
    public void set_position(int [] next_position) { // 根据下一个位置,判断当前位置
	this.position = next_position.clone(); // 因为是数组,指向了同一个源
    }
    
    public int [] get_position() {
	return this.position;
    }
    
    
    // direction = {1, -1, -1, 1}
    // 行走方向,右->下->左->上
    // 注意转角的时候,回到 position
    public void set_next_position(int [] direction) { // 根据方向,判断下一个位置
	this.next_position = this.position.clone();
	
	if(direction[0] == Ants.RIGHT[0]) {   
	    this.next_position[1] = this.position[1] + Ants.RIGHT[0];
	}else if(direction[1] == Ants.DOWN[1]) {
	    this.next_position[0] = this.position[0] - Ants.DOWN[1];   
	}else if(direction[2] == Ants.LEFT[2]) {    
	    this.next_position[1] = this.position[1] + Ants.LEFT[2];
	}else if(direction[3] == Ants.UP[3]){
	    this.next_position[0] = this.position[0] - Ants.UP[3];
	}
    }
    
    public int [] get_next_positon() {
	return this.next_position;
    }
    
    
    
    public void set_direction(int [] direction) { // 设置完方向,更新一下位置
	this.direction = direction;
	this.set_next_position(this.direction);
    }
    
    public int [] getD() {
	return this.direction;
    }
}

public class problem1{
    // 蚂蚁初始化信息
    public static final int [] INIT_POSITION = {1, 1};
    public static final int [] INIT_DIRECTION = {0, 0, 0, 0};
    
    // 地图初始化信息
    public static final int WALL = -1;
    public static final int [][] MATRIX= {{1,2},{3,4}};
    public static final int MATRIX_X_LEN = MATRIX.length;
    public static final int MATRIX_Y_LEN = MATRIX[0].length;
    
    // 蚂蚁下一个方向上是否碰到墙
    public static final int NO_WALL = 1;
    public static final int YES_WALL = 2;
    
    // 一张地图应该四周都是墙,所以比正常矩阵多了两个长度
    public static final int INCREMENT = 2;
  
    public ArrayList<Integer> printMatrix(int [][] matrix) {
	ArrayList<Integer> arr = new ArrayList<>();
	
	int [][] map = initMap(matrix);
	
	// 初始化一只蚂蚁
	int [] position= INIT_POSITION;
	int [] direction = INIT_DIRECTION;
	Ants  ants = new Ants(position, direction);
	
	// 模拟蚂蚁开始爬地图
	// 蚂蚁策略是:
	// 行走方向,右->下->左->上,{1, -1, -1, 1}
	// 走过的地方标记为 -1
	// 遇到 -1 改变方向
	// 直到没有方向可以变换
	int [][] directions = {Ants.RIGHT, Ants.DOWN, Ants.LEFT, Ants.UP};
	int [] next_position = INIT_POSITION;
	
	while(true) {
	    for (int i = 0; i < directions.length; i++) {
		while(find_direction(directions[i], ants, map, arr) == NO_WALL) { 
		    // 如果下一个位置不是墙,就继续在这个方向搜索
		    // 当返回值为 2 时跳出循环,表示碰到了墙,应该更换方向
		}
	    }
	    
	    // 检查四周是否都是墙,当四周都是墙的时候,证明循环结束
	    if(environment(directions, ants, map)) {
		int position_x = ants.get_position()[0];
		int position_y = ants.get_position()[1];
		
		arr.add(map[position_x][position_y]); // 把最后一个元素入栈
		break;
	    }
	}

	return arr;
    }
    
    
    // 蚂蚁在此方向搜索
    public int find_direction(int [] direction, Ants ants, int [][] map, ArrayList<Integer> arr) {
	
	
	if (!isWall(direction, ants, map)) { // 如果下一个位置不是墙, 就更新当前位置
	    				  // 还要将蚂蚁在 map 中的上一个位置设为墙,并保存在 arr 中
	    			     	  // 继续在这个方向上搜索
	    
	    int position_x = ants.get_position()[0];
	    int position_y = ants.get_position()[1];
	    int [] next_position = ants.get_next_positon();
	    
	    arr.add(map[position_x][position_y]);
	    map[position_x][position_y] = WALL;
	    ants.set_position(next_position);
	    printMap(map);
	    
	    return NO_WALL;

	} else { // 否则直接换方向,不更新当前位置
	    return YES_WALL;
	}
	
    }
    
    // 检查四周方向是否都是墙,不是墙返回 false,是墙返回 ture
    // 注意应该根据在当前位置判断下一位置是否是墙,而且把最后一个位置的元素入栈
    public boolean environment(int [][] directions, Ants ants, int [][] map) {
	boolean flag = true;
	for(int i=0; i< directions.length; i++) {
	    if(!isWall(directions[i], ants, map)) { // 只要周围找到一个不是墙,可以退出了
		flag = false;
		break;
	    }
	}
	
	return flag;
    }
    
   
    
    // 检查下一个方向是否墙
    public boolean isWall(int [] direction, Ants ants, int [][] matrix) {
	ants.set_direction(direction);
	
	int next_position_x = ants.get_next_positon()[0];
	int next_position_y = ants.get_next_positon()[1];
	
	if(matrix[next_position_x][next_position_y] == WALL) {
	    return true;
	}else {
	    return false;
	}
    }
    
    // 初始化地图
    public int [][] initMap(int [][] matrix){
	// 先四周设墙
	int[][] map = new int[MATRIX_X_LEN + INCREMENT][MATRIX_Y_LEN + INCREMENT];
	for (int i = 0; i < map[0].length; i++) { // 上下设墙
	    map[0][i] = WALL;
	    map[map.length - 1][i] = WALL;
	}
	
	for(int j = 0; j < map.length; j++) { // 左右设墙
	    map[j][0] = WALL;
	    map[j][map[0].length-1] = WALL;
	}

	
	
	// 设值, 注意不一定是方阵
	for(int i=0; i< MATRIX_X_LEN; i++) {
	    for(int j=0; j< MATRIX_Y_LEN; j++) {
		map[i+1][j+1] = matrix[i][j];
	    }
	}
	
	return map;
    }
    
    // 打印地图
    public void printMap(int [][] matrix) {
	System.out.println("map 过程:");
	for(int i=0; i< MATRIX_X_LEN+INCREMENT; i++) {
	    for(int j=0; j< MATRIX_Y_LEN+INCREMENT; j++) {
		if(matrix[i][j]>0 && matrix [i][j]<10) {
		    System.out.print(matrix[i][j]+"   ");
		}else {
		    System.out.print(matrix[i][j]+"  ");
		}
	    }
	    System.out.println("");
	}
	System.out.println("-------------------");
    }
    
    // 打印数组容器中的值
    public void printArrayList(ArrayList<Integer> arr) {
	System.out.println("容器值:");
	for(int i=0; i< arr.size(); i++) {
	    System.out.print(arr.get(i) + " ");
	}
    }
    
    public static void main(String args[]) {
	problem1 p = new problem1();
	
	p.printMap(p.initMap(MATRIX));

	p.printArrayList(p.printMatrix(MATRIX));
	
	
	
    }
    
    
    
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值