【JS算法】回溯算法

2022-05-05  本文已影响0人  wyc0859

题目:全排列
给定一个不含重复数字的数组 nums ,返回其 所有可能的全排列
输入:nums = [1,2,3] //目标数组
输出:[[1,2,3],[1,3,2],[2,1,3],[2,3,1],[3,1,2],[3,2,1]]

用回溯算法解答,解题思路为:
1、递归函数,结束条件:临时数组(temp)长度==目标数组长度
2、临时数组(temp),往里加目标数组的元素,重复的不要
3、所以for循环,尝试向临时数组加入目标[0] 目标[1] 目标[2]
4、重要的是在递归返回后,从temp弹出一个元素;打印顺序为[1] [1,2] [1,2,3] [1,2][1] 这就是回溯
5、此时再次循环则是[1,3] [1,3,2] [1,3] [1] [ ]

举例1个简单的[1,2]

let cs = 0
let list = []
function test(temp, paramArr) {
  cs++
  if (temp.length === paramArr.length) {
    console.log(`递归第${cs}次-符合条件-结束`);
    cs--  //递归到头了,准备回去,所以cs--
    list.push([...temp])
    return
  }
  for (let i = 0; i < paramArr.length; i++) {
    if (temp.includes(paramArr[i])) {
      continue;
    }
    temp.push(paramArr[i])
    console.log(`递归第${cs}次的f${i}`, temp);
    test(temp, paramArr)
    temp.pop()
    console.log(`递归第${cs}次的f${i}-弹出后`, temp);
  }
  cs-- //本函数执行完毕,所以cs--
}

const paramArr = [1, 2]
test([], paramArr)
console.log("list:", list); //[ [ 1, 2 ], [ 2, 1 ] ]

递归第1次的f0 [ 1 ]
递归第2次的f1 [ 1, 2 ]
递归第3次-符合条件-结束
递归第2次的f1-弹出后 [ 1 ] //第二次调用函数未结束,所以接着走到函数底部
递归第1次的f0-弹出后 []
递归第1次的f1 [ 2 ] //执行第一次的for循环 i=1时
递归第2次的f0 [ 2, 1 ]
递归第3次-符合条件-结束
递归第2次的f0-弹出后 [ 2 ]
递归第1次的f1-弹出后 []


题目:单词搜索

给定一个 二维字符网格 board 和一个字符串单词 word
如果 word 存在于网格中,返回 true ;否则,返回 false
单词必须按照字母顺序,通过相邻的单元格内的字母构成
二维数组: board = [["A","B","C","E"],["S","F","C","S"],["A","D","E","E"]],
目标: word = "ABCCED"

解题思路:
1、双循环得出 行和列坐标,让每个坐标都做为开头 来尝试查找
2、找到第一个,然后上下左右接着找,为了避免又把第1个元素当结果,暂时用null代替
3、没找到则结束这个坐标的操作,把null也回溯恢复,然后开始下一个坐标的查找

var exist = function (board, word) { 
  //设置行列数
  let row = board.length;
  let col = board[0].length;

  //双循环,每个坐标都尝试 作目标的第1元素
  for (let i = 0; i < row; i++) {
    for (let j = 0; j < col; j++) {
      //从宫格图中第一个开始找(i,j),找目标第一个字母(word[0])
      const ret = find(i, j, 0); //返回true或false
      if (ret) {
        return ret;
      }
    }
  }
  return false; //结束了都没找到,就false

  //递归函数,第1个元素符合就接着内部再递归find上下左右找第2元素
  function find(r, c, cur) {
    if (r >= row || r < 0) return false;
    if (c >= col || c < 0) return false;
    if (board[r][c] !== word[cur]) return false; //不是目标元素则false

    //执行到这,说明rc坐标是目标元素;
    //先判断,如果是最后一个也找到了,返true结束
    if (cur == word.length - 1) return true;

    let letter = board[r][c]; //赋给临时变量
    board[r][c] = null; //用null替换做标记,避免下一个找上下左右时重复

    //进行下一步,上下左右查找
    //如:[0][0]是目标第1个元素,这里接着find找[0][1],[1][0]
    //没找到返回false,结束所有find,进入双for中的[0][1]
    const ret =
      find(r - 1, c, cur + 1) ||
      find(r + 1, c, cur + 1) ||
      find(r, c - 1, cur + 1) ||
      find(r, c + 1, cur + 1);
    //用null做标记是避免重复,但双for的find结束就需要恢复
    board[r][c] = letter;
    return ret;
  }
};

这里用回溯是避免重复,导致答案错误

上一篇下一篇

猜你喜欢

热点阅读