题目2019001:

输入一个数字,从1开始到这个数字,顺时针,由内而外旋转打印输出。

示例如图:

RJuzZhenDemo

思路:

1、要求抽象化

首先也是最重要的,我们把这个顺时针旋转输出看成一个矩阵。

50就是一个没填满的 8 * 8 的矩阵。

2、要求简单化

先思考如何输出一个正常的数字矩阵。

JuZheng

基本思路就是先一直向右输出,然后碰到矩阵边,转下,再转左,然后转上,碰到数字后,再左转。

具体代码可以参考:用Python打印旋转数字矩阵

3、要求具体化

相比于普通的顺时针由外而内旋转数字输出,顺时针由内而外旋转输出需要先确定1的位置。

3.1确定原点位置

由于整个图案是一个矩阵,原点位置在最中间。画几个普通示例,来寻找规律。

2JuZhen

3JJuZhen

4JJuZhen

5JJuZhen

6JJuZhen

我们可以发现,原点位置跟N阶矩阵的关系是:(math.ceil(N/2) ,math.ceil(N/2))

math.ceil是向上取整。

3.2 何时旋转

根据几张图我们可以发现,旋转的临界条件有两个。

3.2.1 碰到矩阵边调整方向

3.2.2 碰到局部矩阵边调整方向

局部矩阵就是当输出为num 时,num 所属于的N阶矩阵。

numN的关系是:N = math.ceil(math.sqrt(num))

3.3 存在的四个边界值:

我们需要考虑局部矩阵突破四个角的边界值。

由于我的代码中,默认假设后面一直有数字,所以在取局部N阶矩阵的值时,使用 num + 1,即:

1
N = math.ceil(math.sqrt(num + 1))

考虑局部矩阵边界时,我们可以注意到局部矩阵和整个大矩阵以及原点位置的关系。

犹由于原点位置居中,局部矩阵两边多余行列基本相同,之后得出:

向右及向下的边界:sqrMax - math.floor((sqrMax - colMax) / 2)

向左及向上的边界:math.floor((sqrMax - colMax) / 2) - 1

代码

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
#!/usr/bin/env python3
# -*- coding: utf-8 -*-

import math


def RJuZhen(number):
    # N阶矩阵 N = sqrMax
    sqrMax = math.ceil(math.sqrt(number))
    # 创建2维n*n数组
    a = [[0 for i in range(sqrMax)] for j in range(sqrMax)]
    # print(a)
    # oriRow = oriCol= math.ceil(sqrMax/2) - 1
    # row = oriRow
    # col = oriCol
    # 注意 python 同时赋值时的问题
    row = col = math.ceil(sqrMax / 2) - 1
    flag = 1  # 向右

    for num in range(1, int(number + 1)):
        # 因为临界点上,判断时默认后面继续有数字,所以用 num+1
        rowMax = colMax = math.ceil(math.sqrt(num + 1))
        a[row][col] = num

        if flag == 1:  # 向右,列加1,检测右边是否到矩阵边界。
            col += 1
            if col == sqrMax:
                col = col - 1
                flag = 2  # down 向下,顺时针则第二步要向下
            elif col == sqrMax - math.floor((sqrMax - colMax) / 2):
                col = col - 1
                flag = 2  
        if flag == 2:  #向下
            row += 1
            if row == sqrMax:
                row = row - 1
                flag = 3  #向左
            elif row == sqrMax - math.floor((sqrMax - rowMax) / 2):
                row = row - 1
                flag = 3  
        if flag == 3:  #向左
            col = col - 1
            if col == -1:
                col += 1
                flag = 4
            elif col == math.floor((sqrMax - colMax) / 2) - 1:
                col = col + 1
                flag = 4  #向上
        if flag == 4:  #向上
            row = row - 1
            if row == -1:
                row += 1
                col += 1  #要向右移动一位进行检测
                flag = 1
            elif row == math.floor((sqrMax - rowMax) / 2) - 1:
                row = row + 1
                col = col + 1
                flag = 1

    for i in range(sqrMax):
        for j in range(sqrMax):
            if a[i][j] == 0:
                # \t 制表符,方便对齐。
                print("\t", end="")
            else:
                print(str(a[i][j]) + "\t", end="")
        print("\n")

# 中间数字就是最后的一个数
RJuZhen(36)