1.刷题
46. 全排列
给定一个不含重复数字的数组 nums ,返回其 所有可能的全排列 。你可以 按任意顺序 返回答案。
示例 1:
输入: nums = [1,2,3]
输出: [[1,2,3],[1,3,2],[2,1,3],[2,3,1],[3,1,2],[3,2,1]]
示例 2:
输入: nums = [0,1]
输出: [[0,1],[1,0]]
示例 3:
输入: nums = [1]
输出: [[1]]
答题
/**
* @param {number[]} nums
* @return {number[][]}
*/
function findFun(list,temp,nums) {
if (temp.length == nums.length) {
list.push([...temp])
return
}
for (var i = 0; i < nums.length; i++) {
if(temp.includes(nums[i]))continue
temp.push(nums[i])
findFun(list,temp,nums)
temp.pop()
}
}
var permute = function(nums) {
let list = []
let temp = []
findFun(list,temp,nums)
return list
};
问题解析
核心逻辑
通过temp数组做标识(区分哪些已经使用过),一直递归往下找到所有排列的数组,
当满足长度的时候,记录到全局list,然后通过pop,往上回溯。
79. 单词搜索
给定一个 m x n 二维字符网格 board 和一个字符串单词 word 。如果 word 存在于网格中,返回 true ;否则,返回 false 。
单词必须按照字母顺序,通过相邻的单元格内的字母构成,其中“相邻”单元格是那些水平相邻或垂直相邻的单元格。同一个单元格内的字母不允许被重复使用。
示例 1:
输入: board = [["A","B","C","E"],["S","F","C","S"],["A","D","E","E"]], word = "ABCCED"
输出: true
示例 2:
输入: board = [["A","B","C","E"],["S","F","C","S"],["A","D","E","E"]], word = "SEE"
输出: true
答题
/**
* @param {character[][]} board
* @param {string} word
* @return {boolean}
*/
var exist = function(board, word) {
if(board.length == 0) {
return false
}
if(word.length == 0) {
return true
}
let rowLen = board.length
let colLen = board[0].length
for (let i=0; i < rowLen; i++) {
for (let j=0; j < colLen; j++) {
let flag = find(i,j,0)
if(flag) {
return true
}
}
}
return false
function find(row,col,wordIndex) {
if(row < 0 || col < 0) {
return false
}
if(row >= rowLen || col >= colLen) {
return false
}
let key = board[row][col]
if(key != word[wordIndex]) {
return false
}
if(word.length - 1 == wordIndex) { //已经找到最后一个索引返回找到 ,注意 一定要先判断完 文字是否匹配,再到总长度
return true
}
board[row][col] = null //把当前找到的坐标打上标识
wordIndex ++ //索引递增
//这里只要有一个递归找到true 都算找到
let flag = find(row + 1,col,wordIndex ) ||
find(row - 1,col,wordIndex) ||
find(row,col + 1,wordIndex) ||
find(row,col -1 ,wordIndex) ;
board[row][col] = key //还原标识,以便下次判断可以正常使用判断
return flag
}
};
// console.log(exist([["A","B","C","E"],["S","F","C","S"],["A","D","E","E"]],"ABCB"))
51. N 皇后
- n 皇后问题 研究的是如何将
n个皇后放置在n×n的棋盘上,并且使皇后彼此之间不能相互攻击。 - 给你一个整数
n,返回所有不同的 **n 皇后问题 的解决方案。 - 每一种解法包含一个不同的 n 皇后问题 的棋子放置方案,该方案中
'Q'和'.'分别代表了皇后和空位。
示例 1:
输入: n = 4
输出: [[".Q..","...Q","Q...","..Q."],["..Q.","Q...","...Q",".Q.."]]
解释: 如上图所示,4 皇后问题存在两个不同的解法。
示例 2:
输入: n = 1
输出: [["Q"]]
答题
主要逻辑
[
[1, 2, 3, 4],
[5, 6, 7, 8],
[9,10,11,12],
[13,14,15,16]
]
//注意 索引的 逻辑是先 行 后 列
- 行不能相同
- 列不能相同
- 右斜边不能相同 等价于 0,0 1,1 2,2 等价与 每个节点索引相减都相等
- 左斜边不能相同 等价于 0,3 1,2 2,1 等价与 每个节点索引相加都相等
/**
* @param {number} n
* @return {string[][]}
*/
var solveNQueens = function(n) {
// 通过一维数据就实现二维的摆放逻辑 ,如
// [1,3,0,2] 每一个元素代表哪一行只摆放了那一列。如1 就是 第一行第二个元素
// (成立的提前也是因为每一行和列都一定有内容)
// 等价于
// [[".Q..","...Q","Q...","..Q."]
let ret = [] //ret结果存储多个方案 是二维数组
find(0)
function find(row ,flagArr = [] ){ //按行查询 flagArr 用于临时记录有效摆放的信息,
if( row == n) { //正常 row 最大是n-1 ,也只有row 才能证明 前面所有安放的棋子都是全部正确
let sol = flagArr.map((col,row) => {
let arr = new Array(n).fill(".")
arr[col]= 'Q'
return arr.join("")
})
ret.push( sol)
return
}
for (let col = 0; col < n; col++) {//依次查询每一列
// 主循环是每一列,然后再嵌套循环当前行的下一行
//先检查 当前遍历的列节点是否与 记录表 行和列,斜边冲突碰撞?
// 这里的行不用判断,是因为 当前就在同一行row操作里面的列数据,所以忽略行判断
let isCash = flagArr.some((flagCol,flagRow) => {
if (col === flagCol ||
(col+row === flagCol + flagRow) ||
(col-row === flagCol - flagRow)
) {
return true
}
return false
})
if(isCash) { //证明当前列无效,继续下一列
continue
}
find(row+1,[...flagArr,col]) //当 当前列某个单元没有碰撞,以当前行与下一行一直递归遍历
//flagArr 复制一份
}
}
return ret
};
37解数独
编写一个程序,通过填充空格来解决数独问题。
数独的解法需 遵循如下规则:
- 数字
1-9在每一行只能出现一次。 - 数字
1-9在每一列只能出现一次。 - 数字
1-9在每一个以粗实线分隔的3x3宫内只能出现一次。(请参考示例图)
数独部分空格内已填入了数字,空白格用 '.' 表示。
示例:
输入: board = [["5","3",".",".","7",".",".",".","."],["6",".",".","1","9","5",".",".","."],[".","9","8",".",".",".",".","6","."],["8",".",".",".","6",".",".",".","3"],["4",".",".","8",".","3",".",".","1"],["7",".",".",".","2",".",".",".","6"],[".","6",".",".",".",".","2","8","."],[".",".",".","4","1","9",".",".","5"],[".",".",".",".","8",".",".","7","9"]]
输出: [["5","3","4","6","7","8","9","1","2"],["6","7","2","1","9","5","3","4","8"],["1","9","8","3","4","2","5","6","7"],["8","5","9","7","6","1","4","2","3"],["4","2","6","8","5","3","7","9","1"],["7","1","3","9","2","4","8","5","6"],["9","6","1","5","3","7","2","8","4"],["2","8","7","4","1","9","6","3","5"],["3","4","5","2","8","6","1","7","9"]]
解释: 输入的数独如上图所示,唯一有效的解决方案如下所示:
提示:
board.length == 9board[i].length == 9board[i][j]是一位数字或者'.'- 题目数据 保证 输入数独仅有一个解
答题
/**
* @param {character[][]} board
* @return {void} Do not return anything, modify board in-place instead.
*/
//主循环是 从左到右,上到下,每遇到一个格子,如当前是A格子,试着放入数字1,然后递归循环放入当前A格子以外的所有格子,
//会依次把剩下的所有空格都放入数字,都满足,A格子才保留数字1,同时其他格子也填充完毕,数独填充结束。
//否则一旦有一个无效,当前A格子的1+其他格子已经填入的都回溯还原为数组空'.'内容,返回false,继续下一个数字测试。
var solveSudoku = function(board) {
for (let i = 0; i < 9; i ++) {
for (let j = 0; j < 9; j ++) {
if(board[i][j] !== '.') { //如果当前不为空 ,则跳过
continue
}
for (let k = 1; k <= 9; k++) { //从1-9 取出数字 ,逐个实验
const testNum = k.toString();
if(isValid(board,i,j,testNum)){// 检查当前的行列 是否可以放置
board[i][j] = testNum
if(solveSudoku(board)) { //这里会递归去检查该元素是否穷举有效
return true //这里如果找到了就直接返回,不走下面的还原标识
}
board[i][j] = '.'
}
}
return false //当9个数字都不能放,返回false
}
}
return true //全部可能性都尝试完成 返回true 说明有解
};
//判断整行和整列 与 9宫格 是否可以放 , k是从9个数字中选择的数字
function isValid(board,row,col,k) {
// 由于是9*9 的表格,所以,当前的x,y 坐标统一除3
//检查行+列
for (let i = 0; i < 9; i++) {
if( board[row][i] === k || board[i][col] === k) {
return false
}
}
//检查小方块 x和y 是循环时候的偏移量 ,默认第一个从0,0开始,
const x = Math.floor(row/3)*3
const y = Math.floor(col/3)*3
// 直接找到要判断的小方块 进行比较,是否有重复出现过
for (let i = 0; i < 3; i++) {
for (let j = 0; j < 3; j++) {
if(board[x+i][y+j] === k){
return false
}
}
}
return true
}