一个算法题

回复列表(24|隐藏机器人聊天)
  • @Ta / 2021-11-04 / /

    @老虎会游咏q,19楼的方法似乎就是“动态规划”🤣🤣🤣

    也就是做了前缀优化的排列组合。

    采用逐层遍历+递归的方法生成排列,存储输入参数2元素个数的map通过值传递传给下一层,然后每层都进行取数尝试,一但某层取的数不存在,就从递归里返回false,放弃整个分支,回到下一个分支继续尝试。

    因为存储输入参数2元素个数的map是值传递,所以层与层互不影响,return就能无损回溯。

  • @Ta / 2021-11-04 / /

    继续优化:存储输入参数2元素个数的map也可以引用传递,只需要在return false之前把自己的修改还原就行了。减少的值加回去,就回溯到以前的状态了。

    如果是return true,那就不用还原了,因为答案已经找到了。

    继续优化:
    因为采用引用传递了,所以该算法也可以从递归改成迭代。只需要一个栈记录每层遍历到哪里了就行。递归其实就是在函数调用栈里记录了每层的遍历位置。

  • @Ta / 2021-11-04 / /

    看着老虎说的,按照自己的理解写了一段代码,但是这有个大问题:生成全排列的复杂度是O(n^n)。

    
    // 描述: 手里有一组数字卡片,每个人说出自己想要的一组数字(只能领到一张想要的卡片)。要判断手里的卡片是否能按大家需要分配每一个人。
    function main(desire, gift) {
      const combina = (arr1, arr2) => {
        let arr = [];
        for (let v1 of arr1) {
          for (let v2 of arr2) {
            arr.push(`${v1}${v2}`);
          }
        }
        return arr;
      };
      const generate = (arr, length) => {
        if (length <= 2) {
          return combina(arr[length - 2], arr[length - 1]);
        }
        return combina(generate(arr, length - 1), arr[length - 1]);
      };
      const fullArr = generate(desire, desire.length);
      return fullArr.some((item) => {
        const ngift = [...gift];
        const length = item.split("").length;
        for (let i = 0; i < length; i++) {
          const index = ngift.indexOf(Number(item[i]));
          if (index === -1) break;
          ngift.splice(index, 1);
          if (i === length - 1) {
            return true;
          }
        }
        return false;
      });
    }
    console.log(main([[1, 2], [1, 3], [3]], [1, 3, 4]));
    
    
    

    红米K30 Pro(变焦版)

  • @Ta / 2021-11-04 / /

    老虎也可能说的是这个意思: 回溯加剪枝

    
    // 描述: 手里有一组数字卡片,每个人说出自己想要的一组数字(只能领到一张想要的卡片)。要判断手里的卡片是否能按大家需要分配每一个人。
    function main(desire, gift) {
      const path = [];
      let status = false;
      const dfs = (index) => {
        if (index > desire.length - 1) {
          console.log("递归完成:", path);
          const ngift = [...gift];
          for (let i = 0; i < path.length; i++) {
            const index = ngift.indexOf(path[i]);
            if (index === -1) return;
            ngift.splice(index, 1);
            if (i === path.length - 1) {
              status = true;
            }
          }
          return;
        }
        for (let item of desire[index]) {
          path.push(item);
          console.log("递归前:", path);
          index++;
          dfs(index);
          if (status) {
            return;
          }
          path.pop();
          index--;
          console.log("递归后:", path);
        }
      };
      dfs(0);
      return status;
    }
    console.log(main([[1, 2], [1, 3], [3]], [1, 3, 3]));
    
    

    红米K30 Pro(变焦版)

  • @Ta / 2021-11-04 / /

    提前设置好map,就不需要每次使用indexOf去判断了。

    
    // 描述: 手里有一组数字卡片,每个人说出自己想要的一组数字(只能领到一张想要的卡片)。要判断手里的卡片是否能按大家需要分配每一个人。
    function main(desire, gift) {
      const path = [];
      let status = false;
      const map = {};
      for (let item of gift) {
        if (map[item]) {
          map[item] = map[item] + 1;
        } else {
          map[item] = 1;
        }
      }
      const dfs = (index) => {
        if (status) {
          return;
        }
        if (index > desire.length - 1) {
          console.log("递归完成:", path);
          const nmap = { ...map };
          for (let i = 0; i < path.length; i++) {
            if (nmap[path[i]] && nmap[path[i]] > 0) {
              nmap[path[i]] = nmap[path[i]] - 1;
            } else {
              return;
            }
          }
          status = true;
          return;
        }
        for (let item of desire[index]) {
          path.push(item);
          console.log("递归前:", path);
          index++;
          dfs(index);
          path.pop();
          index--;
          console.log("递归后:", path);
        }
      };
      dfs(0);
      return status;
    }
    console.log(main([[1, 2], [1, 3, 4], [3]], [1, 3, 3]));
    
    
    

    红米K30 Pro(变焦版)

添加新回复
回复需要登录