332. 重新安排行程
/**
* @param {string[][]} tickets
* @return {string[]}
*/
var findItinerary = function (tickets) {
let s = "ZZZ";
let start;
for (let i in tickets) {
if (tickets[i][0] === "JFK" && tickets[i][1] < s) {
start = i;
s = tickets[i][1];
}
}
let count = tickets.length;
let result = [];
let path = [tickets[start]];
let uset = new Array(count);
uset.fill(0);
uset[start] = 1;
backtracing(tickets, uset);
result = result[0];
let road = result[0];
for (let i in result) {
if (i > 0 && i < result.length) road.push(result[i][1]);
}
return road;
function backtracing(tickets, uset) {
if (path.length === count) {
result.push(path.slice());
}
for (let i = 0; i < count; i++) {
if (uset[i]) {
continue;
}
if (path[path.length - 1][1] === tickets[i][0]) {
path.push(tickets[i]);
uset[i] = 1;
backtracing(tickets, uset);
path.pop();
uset[i] = 0;
}
}
}
};
第一想法
如上,可以解决他给的例子(解决了字典和排序),但是不能解决[[“JFK”,“KUL”],[“JFK”,“NRT”],[“NRT”,“JFK”]],按照最小的字典来,没办法
题解(边表桶):
const findItinerary = (tickets) => {
const res = ['JFK']; // 初始放入起点'JFK'
const map = {}; // 邻接表
for (const ticket of tickets) { // 遍历tickets,建表
const [from, to] = ticket; // 每一张机票,读出起点和终点
if (!map[from]) {
map[from] = []; // 初始化
}
map[from].push(to); // 建立映射
}
for (const city in map) { // 按照字母顺序,小的在前
map[city].sort();
}
const dfs = (city, used) => { // city是当前访问的城市、used是已用掉的机票数
if (used == tickets.length) { // 用光了所有机票,路径找到了
return true;
};
const nextCities = map[city]; // 获取下一站能去的城市list
if (!nextCities || nextCities.length == 0) { // 没有邻接城市了
return false; // 还没用光机票,就没有下一站了,返回false
}
for (let i = 0; i < nextCities.length; i++) { // 设置出各种选项(递归分支)
const next = nextCities[i]; // 当前选择的下一站
nextCities.splice(i, 1); // 飞出地的list中删掉这一站
res.push(next); // 将该选择推入res
if (dfs(next, used + 1)) { // 在该递归分支中能找到一个用完所有机票的路径
return true;
} else {
nextCities.splice(i, 0, next); // 将删掉的这一站重新插回去
res.pop(); // 推入res的选择,也撤销
}
}
};
dfs('JFK', 0); // 从'JFK'城市开始遍历,当前用掉0张机票
return res;
};
51. N皇后
/**
* @param {number} n
* @return {string[][]}
*/
result = [];
var solveNQueens = function (n) {
// n 为输入的棋盘大小
// row 是当前递归到棋盘的第几行了
result = [];
let chessboard = new Array(n).fill(0).map(() => new Array(n).fill("."));
backtracking(n, 0, chessboard);
return result;
};
function transformChessBoard(chessBoard) {
let chessBoardBack = [];
chessBoard.forEach((row) => {
let rowStr = "";
row.forEach((value) => {
rowStr += value;
});
chessBoardBack.push(rowStr);
});
return chessBoardBack;
}
function backtracking(n, row, chessboard) {
if (row === n) {
result.push(transformChessBoard(chessboard));
return;
}
for (let col = 0; col < n; col++) {
if (isValid(row, col, chessboard, n)) {
// 验证合法就可以放
chessboard[row][col] = "Q"; // 放置皇后
backtracking(n, row + 1, chessboard);
chessboard[row][col] = "."; // 回溯,撤销皇后
}
}
}
function isValid(row, col, chessboard, n) {
// 列
for (let i = 0; i < row; i++) {
//注意i<row
if (chessboard[i][col] === "Q") {
return false;
}
}
// 45度
for (let i = row - 1, j = col - 1; i >= 0 && j >= 0; i--, j--) {
if (chessboard[i][j] === "Q") {
return false;
}
}
// 135度
for (let i = row - 1, j = col + 1; i >= 0 && j < n; i--, j++) {
if (chessboard[i][j] === "Q") {
return false;
}
}
return true;
}
思想
困难
传到最后,chessbord回溯了,全部回到了过去。
所以另开一个数组去记载chessBoardBack = [];
37.解数独
var solveSudoku = function(board) {
function isValid(row, col, val, board) {
let len = board.length
// 行不能重复
for(let i = 0; i < len; i++) {
if(board[row][i] === val) {
return false
}
}
// 列不能重复
for(let i = 0; i < len; i++) {
if(board[i][col] === val) {
return false
}
}
let startRow = Math.floor(row / 3) * 3
let startCol = Math.floor(col / 3) * 3
for(let i = startRow; i < startRow + 3; i++) {
for(let j = startCol; j < startCol + 3; j++) {
if(board[i][j] === val) {
return false
}
}
}
return true
}
function backTracking() {
for(let i = 0; i < board.length; i++) {
for(let j = 0; j < board[0].length; j++) {
if(board[i][j] !== '.') continue
for(let val = 1; val <= 9; val++) {
if(isValid(i, j, `${val}`, board)) {
board[i][j] = `${val}`
if (backTracking()) {
return true
}
board[i][j] = `.`
}
}
return false
}
}
return true
}
backTracking(board)
return board
}