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 integer
n
To generate a contain1
到n2
All the elements, and the elements are arranged in a clockwise spiral ordern x n
Square 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
- Input matrix dimension
n
. - The algorithm generates a result matrix or array
resMatrix
And save the results of each step toresObj
In the object. - Using the Grid layout will
wrap
Divide into n by N grids of the same size. - in
wrap
N by nbox
, set its transparency to 0, andresMatrix
Corresponds to the values in. index
The initial value is 1setInterval
controlindex
If,box
The text value ofindex
, it willbox
Display, set the background color, and add a simple animation effect.resObj
In the same directionbox
The 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.