剥洋葱

1. 题目信息

输入:
    3
输出:
    AAAAA
    ABBBA
    ABCBA
    ABBBA
    AAAAA
注意点:
    1. 输入的数表示图形的层数
    2. 字符为A-Z, 从外到里排列

2. 题目分析

1个字母的情况:

[
    [C]
]

2个字母的情况:

[
    [B, B, B],
    [B, C, B],
    [B, B, B]
]

3个字母的情况:

[
    [A, A, A, A, A]
    [A, B, B, B, A]
    [A, B, C, B, A]
    [A, B, B, B, A]
    [A, A, A, A, A]
]

对于这个演变过程我们发现: 每次都是在上一层的基础上, 再累加一层数据, 我们如果用代码解决这个问题, 我们只需要按照这个逻辑即可;

3. 代码

const log = console.log.bind(console)

const getList = (char, length) => {
    let result = []
    for (let i = 0; i < length; i++) {
        result.push(char)
    }
    return result
}

const dealCenterContent = (char, result) => {
    for (let j = 1; j < result.length - 1; j++) {
        result[j].unshift(char)
        result[j].push(char)
    }
}

const createGraphics = (number) => {
    let list = ['A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z']
    let result = [[]]

    for (let i = number - 1; i > -1; i--) {
        let len = result[0].length
        let char = list[i]

        // 最开始的特殊情况
        if (i === number - 1){
            result[0][0] = char
            continue
        }

        let head = getList(char, len + 2)
        let end = getList(char, len + 2)
        result.unshift(head)
        result.push(end)

        dealCenterContent(char, result)
    }

    return result
}

const __main = () => {
    let number = 3
    log(createGraphics(number))
}

__main()

4. 感悟

其实这种算法题很少写思路之外的其他东西, 但是这个算法题很特殊, 其实这个算法题难度并不高, 自己很早之前就做了;

做题思路: https://blog.csdn.net/hcy2319964421/article/details/53106578

我记得之前做这个题目应该是花了2 小时以上, 那时自己刚学编程, 喜欢这种纯粹逻辑 + 规律的思维去解决问题, 但是这种思维的局限性很大:

  1. 单纯的数学规律会让你忽视递归和循环在作用
  2. 有些题目, 数学规律比较繁琐,会随着数据量的增多而变得复杂.

我甚至很长时间都是这样去思考的, 但是, 今天看到交流群中一个前辈的代码, 我突然有点豁然开朗的感觉:
对于这种题目: 应该寻找一种解决方式, 适用于所有情况,

例如这个题目: 每一次累加都是在最外层, 那么我们只需要给上一次的数据加上一个最外层就可以了.

这里我们发散一下: 我们想象一下编程的本质到底是什么? 我们先来看一组名词

  1. 变量
  2. 函数
  3. 对象
  4. UI框架
  5. 计算机

上面这一组名词, 其实存在着一个共同的特点, 它们存在的意义之一就是为了消除重复.

  1. 变量的存在是为了消除一个数/对象 重新引用的问题;
  2. 函数的存在是抽象了一种数据的处理方式
  3. 对象的存在是为了抽象一类事物的共同点
  4. UI 框架的存在是为了预定义一些基本的元素类, 加速项目的开发
  5. 计算机的存在是为了计算, 简而言之就是消除人类需要的重复运算

编程其实解决的最大问题就是消除重复.
我们做的应该是, 找到一种解决方法, 它适用于一个特殊场景; 而对于其他不是改场景的内容, 我们可以将其改造成为这个场景

5. 小彩蛋

将上面代码的 createGraphics 函数作如下更改, 输出内容将会变得非常奇怪, 思考一下这是为什么
更改:

const createGraphics = (number) => {
    let list = ['A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z']
    let result = [[]]

    for (let i = number - 1; i > -1; i--) {
        let len = result[0].length
        let char = list[i]

        // 最开始的特殊情况
        if (i === number - 1){
            result[0][0] = char
            continue
        }

        let head = getList(char, len + 2)
        // let end = getList(char, len + 2)
        result.unshift(head)
        result.push(head)

        dealCenterContent(char, result)
    }

    return result
}

输出内容:

[
  [ 'A', 'A', 'A', 'A', 'A' ],
  [ 'A', 'A', 'B', 'B', 'B', 'A', 'A' ],
  [ 'A', 'B', 'C', 'B', 'A' ],
  [ 'A', 'A', 'B', 'B', 'B', 'A', 'A' ],
  [ 'A', 'A', 'A', 'A', 'A' ]
]

6. 提示

因为这个, 写该题时, 自己花费了15分钟DeBug(水平堪忧......┭┮﹏┭┮)
说来也是很奇怪, 这个性质自己是知道的, 为什么DeBug 的时候就是想不起来呢

const log = console.log.bind(console)

let a = [1, 2, 3]
let b = [[4, 5, 6]]
b.unshift(a)
b.push(a)
log(b) // [ [ 1, 2, 3 ], [ 4, 5, 6 ], [ 1, 2, 3 ] ]
b[0].push(7)
log(b) // [ [ 1, 2, 3, 7 ], [ 4, 5, 6 ], [ 1, 2, 3, 7 ] ]