preface

These days, I have been looking at LeetCode, and found the spiral matrix ⅱ, which is marked as medium difficulty, as shown below.

I’ll give you a positive integernTo generate a contain1 到 n2All the elements, and the elements are arranged in a clockwise spiral ordern x nSquare matrixmatrix 。

The sample



The input: n = 3

The output8,9,4: [[1, 2, 3], [], [7,6,5]]

But there’s no algorithm involved, it’s just a simple simulation. Start filling numbers from the initial position (Matrix[0][0]), and the initial direction is to the right to control the change of column vectors. Then judge whether the next position, namely Matrix[0][1], is a boundary or has been filled. If no, continue filling; if yes, change the direction and control the change of row vector. After repeated operation can be.

The solution is as follows:

/ * * *@param {number} n
 * @return {number[][]}* /
var generateMatrix = function(n) {
    let res = new Array(n).fill(0).map(() = > new Array(n).fill(0));
    
    let maxNum = n * n
    let nowNum = 1;
    let currentX = 0,currentY = 0;
    let directions = [[0.1], [1.0], [0, -1], [...1.0]] // Lower right and upper left
    let moveIndex = 0

    while(nowNum <= maxNum){
        res[currentX][currentY] = nowNum ++
        let nextX = currentX + directions[moveIndex][0]
        let nextY = currentY + directions[moveIndex][1]
        if(nextX >= n || nextY >= n || nextX < 0 || nextY < 0|| res[nextX][nextY]! =0)
            moveIndex = (moveIndex + 1 ) % 4
        currentX = currentX + directions[moveIndex][0]
        currentY = currentY + directions[moveIndex][1]}return res
};
Copy the code

Of course, we’re not here to share how this problem works. I also used HTML+CSS+JS to visualize the process just now.

Train of thought

  1. Input matrix dimensionn.
  2. The algorithm generates a result matrix or arrayresMatrixAnd save the results of each step toresObjIn the object.
  3. Using the Grid layout willwrapDivide into n by N grids of the same size.
  4. inwrapN by nbox, set its transparency to 0, andresMatrixCorresponds to the values in.
  5. indexThe initial value is 1setIntervalcontrolindexIf,boxThe text value ofindex, it willboxDisplay, set the background color, and add a simple animation effect.resObjIn the same directionboxThe background color is the same.

Implementation effect

GIF toolScreenToGif

The complete code

<! DOCTYPEhtml>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="Width = device - width, initial - scale = 1.0">
    <title>Spiral matrix ⅱ</title>
    <style>
        * {
            margin: 0;
            padding: 0;
        }

        body {
            width: 100vw;
            height: 100vh;
            background-color: #bdc3c7;
            display: flex;
            justify-content: center;
            align-items: center;
            flex-direction: column;
        }

        input {
            width: 500px;
            padding: 20px;
            font-size: 20px;
            box-sizing: border-box;
            border: none;
            outline: none;
        }

        .main {
            margin-top: 50px;
            display: flex;
            justify-content: center;
            position: relative;
        }

        .wrap {
            width: 500px;
            height: 500px;
            display: grid;
            gap: 5px;
            position: relative;
            overflow: hidden;
        }

        .wrap-trans::before {
            content: "";
            position: absolute;
            width: 50px;
            height: 100%;
            background: linear-gradient(0deg.rgba(255.255.255.0),rgba(255.255.255.0.5),rgba(255.255.255.0));
            z-index: 2;
            animation: twinkle .5s forwards;
        }

        .message {
            width: 300px;
            max-height: 500px;
            overflow-y: scroll;
            box-sizing: border-box;
            padding: 0 30px;
            position: absolute;
            right: -300px;
            color: #34495e;
            font-size: 12px;
            line-height: 30px;
        }

        /* Set the scroll bar style */
        /* Scrollbar overall style */
        .message::-webkit-scrollbar{
            width: 5px;
            height: 1px;
        }
        /* Scroll bar inside the small square */
        .message::-webkit-scrollbar-thumb{
            border-radius: 4px;
            box-shadow: inset 0 0 5px rgba(0.0.0.0.2);
            background: #bdc3c7;
        }

        .box {
            display: flex;
            justify-content: center;
            align-items: center;
            background-color: #fff;
            font-size: 24px;
            color: #34495e;
            font-weight: bold;
        }

        .showAnimation {
            animation-name: showBox;
            animation-duration:.5s;
            animation-fill-mode: forwards;
        }

        @keyframes showBox {
            from{
                opacity: 0;
            }
            to{
                opacity: 1; }}@keyframes twinkle {
            from{
                transform: translateX(0);
            }
            to{
                transform: translateX(520px); }}</style>
</head>
<body>
    <input type="text" id="inputEl" placeholder="Please enter matrix dimensions (1-10)...">
    <div class="main">
        <div class="wrap"></div>
        <div class="message"></div>
    </div>

    <script>
        const DELAY = 100
        const colors = ['#1abc9c'.'#f1c40f'.'#e84393'.'#e67e22'.'#3498db'.'#e74c3c'.'#9b59b6'.'#fab1a0'.'#95a5a6']

        let resMatrix;
        let resObj

        inputEl.onkeyup = function(e){
            var e = e || window.event
            if(e.keyCode == 13) {let n = parseInt(inputEl.value)
                if(n >= 1 && n <= 10) {let wrap = document.querySelector('.wrap')
                    resMatrix = createMatrix(n)
                    clearDom(wrap)
                    updateGrid(wrap,n)
                    createDom(wrap,n)
                    showBox(n)
                }else
                    alert('Please enter an integer between 1 and 10')}}function updateGrid(dom,n){
            dom.style.gridTemplateRows = `repeat(${n},1fr)`
            dom.style.gridTemplateColumns = `repeat(${n},1fr)`
        }

        function clearDom(dom){
            while(dom.hasChildNodes()){ dom.removeChild(dom.firstChild); }}function createDom(dom,n){
            for(let i=0; i<n; i++){for(let j=0; j<n; j++){let box = document.createElement('div')
                    box.innerHTML = resMatrix[i][j]
                    box.classList.add('box')
                    // box.setAttribute('data-index',resMatrix[i][j])
                    box.style.opacity = '0'
                    dom.appendChild(box)
                }
            }
        }

        function showBox(n){
            let boxArray = Array.from(document.querySelectorAll('.box'))
            let messageBox = document.querySelector('.message')
            let index = 1

            messageBox.innerText = ""

            let timer = setInterval(() = > {
                if(index == n*n){
                    clearInterval(timer);
                    document.querySelector('.wrap').classList.add('wrap-trans')
                    setTimeout(() = > {
                        document.querySelector('.wrap').classList.remove('wrap-trans')},1000);
                }
                
                let nowBox = boxArray.filter(item= > {
                    // return item.getAttribute('data-index') == index
                    return item.innerHTML == index
                })
                nowBox[0].classList.add('showAnimation')
                nowBox[0].style.background = colors[resObj[index] % colors.length]
                messageBox.innerText += 'filling${index}, adjust the direction${resObj[index]}Times. \n`
                messageBox.scrollTop = messageBox.scrollHeight;
                index ++
            }, DELAY);
        }

        function createMatrix(n){
            let res = new Array(n).fill(0).map(() = > new Array(n).fill(0));

            resObj = {}
            let maxNum = n * n
            let nowNum = 1;
            let currentX = 0,currentY = 0;
            let directions = [[0.1], [1.0], [0, -1], [...1.0]] // Lower right and upper left
            let moveIndex = 0
            let step = 0

            while(nowNum <= maxNum){
                res[currentX][currentY] = nowNum ++
                let nextX = currentX + directions[moveIndex][0]
                let nextY = currentY + directions[moveIndex][1]
                if(nextX >= n || nextY >= n || nextX < 0 || nextY < 0|| res[nextX][nextY]! =0){
                    moveIndex = (moveIndex + 1 ) % 4
                    step ++
                    resObj[nowNum-1] = step
                }else{
                    resObj[nowNum-1] = step
                }
                currentX = currentX + directions[moveIndex][0]
                currentY = currentY + directions[moveIndex][1]}return res
        }

    </script>
</body>
</html>
Copy the code

conclusion

The above implementation is to generate all the boxes at once and hide them, and then display them through the timer. But when I was writing, because I did not control the size of the dimension at the beginning, I accidentally entered 123, resulting in the page directly stuck 😂

There’s another way to think about it — generate boxes one by one, and do it when it’s your turn. However, as a result, since the boxes are arranged in order, the first row is finished, and the first column of the second row is directly started, so the desired effect cannot be achieved. Of course, it seems that the grid-area can also be used to fix the location of each box, which may also be a kind of idea, but I set the maximum dimension to 10. There may not be much difference in speed.