🚀 前言
大家好呀,我是毛小悠,可以叫我二毛,在家中排行老二,是一名前端开发工程师。
本系列文章旨在通过练习来提高JavaScript的能力,一起愉快的做题吧。😀😀😀
以下每道题,二毛我都有尝试做一遍。建议限时训练,比如限定为半小时,如果半小时内想不出来,可以结合文章末尾的参考答案来思考。
可以在下方评论区留言或者加我的微信:code\_maomao。期待你的到来。
求关注求点赞👍\~~~😘😘😘
📖 题目1:单词搜索难题挑战
单词搜索是经典的儿童拼图游戏,您需要在其中找到水平、垂直或对角线隐藏在随机字母网格中的单词列表。
单词“ dog”,“ cat”和“ parrot”都隐藏在下面的单词搜索拼图网格中。
A B C D E F G H
1 F H K E F F H D
2 F D O G I O P V
3 F J D K O I A Q
4 F J E I H Q R M
5 C W B X X N R I
6 A A E S F U O F
7 C U T H E S T U
8 F J J S N J I O
参数:
系统会为您提供单词列表:['DOG','CAT','PARROT']和代表方形字母网格的字符串:'FHKEFFHDFDOGIOPVFJDKOIAQFJEIHQRMUWTXXNRIAAESFUOFCUHHESTUFJJSNJIO'。
拼图字符串全部大写,并且不包含空格或网格标题(例如,在上面的可视示例中,列A-H和行1-8)。
单词只会在水平,垂直或对角线的左右方向上拼写。
假设网格拼图将始终是一个理想的正方形,最小尺寸为4x4,最大尺寸为26x26(A-Z列)。
您的挑战:
您必须返回一个数组的子数组,该数组代表每个单词的每个字母的网格位置。行用数字表示。列用字母表示。
在上面的示例中,解决方案为:[[B2,C2,D2],[A5,B6,C7,],[G2,G3,G4,G5,G6,G7]]
如果在拼图中找不到单词,则其位置子数组应显示为['找不到单词。']。例如:
[[B2,C2,D2],['找不到单词。],[G2,G3,G4,G5,G6,G7]]]
您可以假设任何一个谜题中都不会隐藏重复的单词。
习题代码:
function wordSearch(words, puzzle) {
// your code goes here.
}
答案
🍗 题目1的答案
参考答案1:
function wordSearch(words, puzzle) {
var s=Math.sqrt(puzzle.length), m = puzzle.match(new RegExp(`.{${s}}`,'g'));
return words.map(w=>{
for(let j=0; j<s; j++) for(let i=0; i<s; i++) {
var r=true, d=true, v=true;
if(i+w.length<=s) {
for(let k=0; k<w.length; k++) if(m[j][i+k]!==w[k]) r=false;
if(r) return [...Array(w.length)].map((_,k)=>[i+k,j]);
}
if(j+w.length<=s) {
for(let k=0; k<w.length; k++) if(m[j+k][i]!==w[k]) d=false;
if(d) return [...Array(w.length)].map((_,k)=>[i,j+k]);
}
if(i+w.length<=s&&j+w.length<=s) {
for(let k=0; k<w.length; k++) if(m[j+k][i+k]!==w[k]) v=false;
if(v) return [...Array(w.length)].map((_,k)=>[i+k,j+k]);
}
}
return -1;
}).map(r=>r===-1?['Word not found.']:r.map(([i,j])=>'ABCDEFGHIJKLMNOPQRSTUVWXYZ'[i]+(j+1)));
}
参考答案2:
function buildGrid(puzzle, sideSize) {
const regex = new RegExp(`[A-Z]{${sideSize}}`, 'g');
return puzzle.match(regex);
}
function buildCoords(sideSize) {
const alpha = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ';
const letters = [...alpha.slice(0, sideSize)];
let coords = [];
for (let num = 1; num <= sideSize; num++) {
let row = letters.map(letter => letter + String(num));
coords.push(row);
}
return coords;
}
function getCols(grid) {
return [...grid[0]].map((_, colIdx) => {
return grid.map(row => row[colIdx])
.join('');
});
}
function getDiagonals(rows) {
rows = rows.map(row => [...row]);
const sideSize = rows.length;
let shiftFromLast = true;
let rowCounts = [];
for (let count = 1; count < sideSize; count++) {
rowCounts.push(count);
}
for (let count = sideSize; count >= 1; count--) {
rowCounts.push(count);
}
const diagonals = rowCounts.map(rowCount => {
let targetRows = shiftFromLast ? rows.slice(-rowCount) : rows.slice(0, rowCount);
if (rowCount === sideSize) shiftFromLast = false;
let diagonal = targetRows.map(row => row.shift());//.join('');
return diagonal;
});
return diagonals;
}
function getGridDiagonals(grid) {
let rows = grid.map(rowStr => [...rowStr]);
return getDiagonals(rows);
}
function getCoordDiagonals(gridCoords) {
return getDiagonals(gridCoords);
}
function searchRows(grid, gridCoords, word) {
const targetRow = grid.findIndex(row => row.includes(word));
if (targetRow !== -1) {
let wordStart = grid[targetRow].search(word);
let wordStop = wordStart + word.length;
return gridCoords[targetRow].slice(wordStart, wordStop);
} else {
return null;
}
}
function searchCols(grid, gridCoords, word) {
const gridCols = getCols(grid);
const coordCols = [...grid[0]].map((_, colIdx) => {
return gridCoords.map(row => row[colIdx]);
});
const targetCol = gridCols.findIndex(col => col.includes(word));
if (targetCol !== -1) {
let wordStart = gridCols[targetCol].search(word);
let wordStop = wordStart + word.length;
return coordCols[targetCol].slice(wordStart, wordStop);
} else {
return null;
}
}
function searchDiagonals(grid, gridCoords, word) {
const gridDiagonals = getGridDiagonals(grid);
const coordDiagonals = getCoordDiagonals(gridCoords);
const targetDiagonal = gridDiagonals.map(diagonal => diagonal.join(''))
.findIndex(diagonal => diagonal.includes(word));
if (targetDiagonal !== -1) {
let wordStart = gridDiagonals[targetDiagonal].join('').search(word);
let wordStop = wordStart + word.length;
return coordDiagonals[targetDiagonal].slice(wordStart, wordStop);
} else {
return null;
}
}
function wordSearch(words, puzzle) {
const sideSize = Math.sqrt(puzzle.length);
const grid = buildGrid(puzzle, sideSize);
const gridCoords = buildCoords(sideSize);
const letterCoords = words.map (word => {
if (searchRows(grid, gridCoords, word) !== null) {
return searchRows(grid, gridCoords, word);
} else if (searchCols(grid, gridCoords, word) !== null) {
return searchCols(grid, gridCoords, word);
} else if (searchDiagonals(grid, gridCoords, word) !== null) {
return searchDiagonals(grid, gridCoords, word);
} else {
return ['Word not found.'];
}
});
return letterCoords;
}
参考答案3:
// Approach:
//
// Create a tree of all potential paths for a given word and pick first path
// that has all letters traveling in same direction.
// Paths can go east ("across"), south ("down") or southeast ("diagonal").
// First level of tree is the first letter of the word, anywhere in the puzzle.
// Continue building tree from there, one letter of the word at a time.
// Main Program
function wordSearch(words, puzzle) {
const grid = new Grid(puzzle);
grid.init();
return words.map((word) => {
return grid.search(word);
});
}
// Classes and helper functions
class Node {
constructor(letter, x, y, parent, direction) {
this.letter = letter;
this.x = x;
this.y = y;
this.parent = parent;
this.direction = direction;
}
}
class Grid {
constructor(puzzle) {
this.size = Math.sqrt(puzzle.length);
this.puzzle = puzzle;
this.grid = [];
this.showPuzzle();
}
init() {
const size = this.size;
for (let i = 0; i < size; i++) {
this.grid.push(this.puzzle.substring(i * size, i * size + size));
}
}
showPuzzle() {
let topLabel = '';
for (let i = 0; i < this.size; i++) {
topLabel += String.fromCharCode(65 + i);
}
console.log(' ', topLabel);
for (let i = 0; i < this.size; i++) {
let rowLabel = '';
if (i+1 < 10) {
rowLabel = ` ${i+1}`;
} else {
rowLabel = `${i+1}`;
}
console.log(rowLabel, this.puzzle.substring(i * this.size, i * this.size + this.size));
}
console.log();
}
search(word) {
// create a tree with root node that points to all first letters of the word
// search for 2nd letter to east, south and south-east
// continue until word is done
// follow the leaf note back to the root to find the path
console.log(`Searching for '${word}'...`);
const rootNode = new Node();
let leafNodesQueue = [];
// find all the first letters
const firstLetter = word[0];
for (let x = 0; x < this.size; x++) {
for (let y = 0; y < this.size; y++) {
if (this.grid[y][x] === firstLetter) {
const node = new Node(firstLetter, x, y, root);
leafNodesQueue.push(node);
}
}
}
// loop from 2nd letter to end of the word
for (let i = 1; i < word.length; i++) {
const newLeafs = [];
if (leafNodesQueue.length === 0) {
// short circuit, word not found
break;
}
// loop through all the leaf nodes
// discover if next letter is east, south or southeast
while (leafNodesQueue.length) {
const leaf = leafNodesQueue.pop();
const { x, y } = leaf;
if (x < this.size - 1 && this.grid[y][x + 1] === word[i]) {
const node = new Node(word[i], x + 1, y, leaf, 'east');
newLeafs.push(node);
}
if (y < this.size - 1 && this.grid[y + 1][x] === word[i]) {
const node = new Node(word[i], x, y + 1, leaf, 'south');
newLeafs.push(node);
}
if (x < this.size - 1 && y < this.size - 1 && this.grid[y + 1][x + 1] === word[i]) {
const node = new Node(word[i], x + 1, y + 1, leaf, 'southeast');
newLeafs.push(node);
}
} // end while
leafNodesQueue = newLeafs;
}
// ensure we only capture paths where letters are all going in one direction
const validResults = [];
while (leafNodesQueue.length) {
let result = [];
const leaf = leafNodesQueue.pop();
findPath(leaf, result);
const officialDirection = result[0].direction;
let ok = true;
for (let i = result.length - 2; i > 0; i--) {
if (result[i].direction !== officialDirection) {
ok = false;
}
}
if (ok) {
validResults.push(result);
break; // only need one valid result
}
}
// if we have at least one solution, grab first one
if (validResults.length) {
return validResults[0].reverse().map((node) => {
return node.location;
});
}
return ['Word not found.'];
}
}
function findPath(node, result) {
if (node === undefined) {
return;
}
// only push on nodes that have letters (to skip adding root node)
if (node.letter) {
result.push({ direction: node.direction, location: `${String.fromCharCode(65 + node.x)}${node.y+1}`, letter: node.letter });
}
return findPath(node.parent, result);
}
参考答案4:
function wordSearch(words, puzzle) {
const position = []
const arr = puzzle.split('')
const gridLenght = Math.pow(arr.length, 0.5)
// create Grid.
const gridHoriz = arr.reduce(function(result, value, index, array) {
if (index % gridLenght === 0)
result.push(array.slice(index, index + gridLenght));
return result;
}, []);
const gridVert = []
for(let i = 0; i< gridHoriz.length; i++) {
const line = []
for(let j = 0; j < gridHoriz.length; j ++) {
line.push(gridHoriz[j][i])
}
gridVert.push(line)
}
const diagonal = (array) => {
const gridLength = array.length
const rowLength = array[0].length
const maxLength = Math.max(rowLength, gridLength)
const gridDiag = []
for(let i = 0; i <= 2 * (maxLength - 1) ; ++i){
let temp = []
for(let j = gridLength - 1; j >=0; --j) {
const foo = i - (gridLength - j)
if(foo >= 0 && i - (gridLength - j) < rowLength) {
temp.push(array[j][foo])
}
}
if(temp.length > 0 ) {
gridDiag.push(temp.reverse())
}
}
return gridDiag
}
const gridDiagonal = diagonal(gridHoriz)
const addPosition = (grid, gridName) => {
return grid.map((row, rowIndex) => {
return row.map( (letter, letterIndex) => {
const alphabet = (gridName === 'gridVert') ? String.fromCharCode(rowIndex+1 + 64) : String.fromCharCode(letterIndex+1 + 64)
const obj ={}
const position = (gridName === 'gridVert') ? `${alphabet}${letterIndex + 1}` : `${alphabet}${rowIndex + 1}`
obj[position] = letter
return obj
})
})
}
const gridHorizPosition = addPosition(gridHoriz, 'gridHoriz' )
const gridVertPosition = addPosition(gridVert,'gridVert' )
const gridDiagonalPosition = diagonal(gridHorizPosition)
const gridMaster = [gridDiagonal, gridVert, gridHoriz]
const gridMasterPosition = [gridDiagonalPosition, gridVertPosition, gridHorizPosition]
words.map((word, index) => {
const temp = []
for(let i =0 ; i < gridMaster.length; i++){
for(let j = 0; j < gridMaster[i].length; j++) {
const string = gridMaster[i][j].join('')
if(string.includes(word)) {
const wordStart = string.search(word)
const rowPosition = gridMaster[i].indexOf(gridMaster[i][j])
for(let f = 0 ; f < word.length; f++) {
const coordinate = Object.keys(gridMasterPosition[i][rowPosition][wordStart + f])[0]
temp.push(coordinate)
}
}
}
}
(temp.length > 0 ) ? position.push(temp) : position.push(['Word not found.'])
})
return position
}
参考答案5:
function wordSearch(words, puzzle) {
function horizontal(word) {
for (let row = 0; row < side; row++) {
const pos = puzzleH[row].indexOf(word)
if (pos !== -1) {
const answer = []
const row2 = row + 1
for (let i = 0, len = word.length; i < len; i++) {
answer.push(String.fromCharCode((pos + i) + A) + row2)
}
return answer
}
}
return []
}
function vertical(word) {
for (let col = 0; col < side; col++) {
const pos = puzzleV[col].indexOf(word)
if (pos !== -1) {
const answer = []
const col2 = String.fromCharCode(col + A)
for (let i = 0, len = word.length; i < len; i++) {
answer.push(col2 + (pos + 1 + i))
}
return answer
}
}
return []
}
function diagonal(word) {
const len = word.length
const max = side - len
let found = false
let foundRow = -1
let foundCol = -1
for (let col = 0; col <= max; col++) {
let s = "";
for (let col2 = col; col2 < side; col2++) {
s += puzzleH[col2 - col][col2]
}
let pos = s.indexOf(word)
if (pos !== -1) {
found = true
foundRow = pos + 1
foundCol = col + pos
break
}
}
for (let row = 1; row <= max; row++) {
let s = "";
for (let row2 = row; row2 < side; row2++) {
s += puzzleH[row2][row2 - row]
}
let pos = s.indexOf(word)
if (pos !== -1) {
found = true
foundRow = row + pos + 1
foundCol = pos
break
}
}
let answer = []
if (found) {
for (let i = 0; i < len; i++) {
answer.push(String.fromCharCode((foundCol + i) + A) + (foundRow + i))
}
}
return answer
}
const side = Math.sqrt(puzzle.length)
const puzzleArray =puzzle.split('')
const puzzleH =[...Array(side).keys()].map(row => {
const start = row * side;
return puzzleArray.slice(start, start + side).join('')
})
const puzzleV =[...Array(side).keys()].map(col => puzzleArray.filter((letter, i) => i % side === col).join(''))
const A = 'A'.charCodeAt(0)
// console.log(puzzleH)
// console.log(puzzleV)
const results = []
for (const word of words) {
let found = false
const hres = horizontal(word)
if (hres.length > 0) {
found = true
results.push(hres)
}
const vres = vertical(word)
if (vres.length > 0) {
found = true
results.push(vres)
}
const dres = diagonal(word)
if (dres.length > 0) {
found = true
results.push(dres)
}
if (!found) {
results.push(['Word not found.'])
}
}
return results
}
🍁后序
本系列会定期更新的,题目会由浅到深的逐步提高。
求关注求点赞 👍~~🍭🍭🍭
可以关注我的公众号:前端毛小悠。欢迎阅读
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。