力扣每日一题 特别的排列 DFS 记忆化搜索 位运算 状态压缩DP

Problem: 2741. 特别的排列
在这里插入图片描述

👨‍🏫 参考题解

🍻 暴搜

⏰ 时间复杂度: O ( N ) O(N) O(N)

class Solution {
    public int specialPerm(int[] nums) {
     
      boolean[] visited = new boolean[nums.length];
      return dfs(nums, 0, -1, visited);
    }
    // dfs(depth, prevPos) 定义为: 0到第depth个位置的特殊排列最后一位下标为prevPos 的特殊排列的总数目。
    private int dfs(int[] nums, int depth, int prevPos, boolean[] visited) {
    // 如果能枚举完整个数组,意味着这个排列是满足条件的特殊排列,那么返回一种方案
      if(depth == nums.length) {
        return 1;
      }
      int res = 0;
      for(int i = 0; i < nums.length; i++) {
        if(!visited[i]) {
            // 第0个数不需要考虑是否满足条件
          if (prevPos == -1 || nums[prevPos] % nums[i] == 0 || nums[i] % nums[prevPos] == 0) {
            visited[i] = true;
            res = (res + dfs(nums, depth + 1, i, visited)) % 1000000007;
            visited[i] = false;
          }
        }
      }
      return res;
    }
}

🍻 记忆化搜索

在这里插入图片描述

class Solution {

  public int specialPerm(int[] nums) {
    int n = nums.length;
    Map<String, Integer> memo = new HashMap<>(); 
    boolean[] visited = new boolean[nums.length];
    return dfs(nums, 0, -1, visited, 0, memo);

  }
  // dfs(depth, prevPos, u) 定义为: 0到第depth个位置的特殊排列最后一位下标为为prevPos,且排列对应的二进制占位为u,确定depth位的特殊排列的总数目。
  private int dfs(int[] nums, int depth, int prevPos, boolean[] visited, int u, Map<String, Integer> memo) {
    if(depth == nums.length) {
      return 1;
    }
    // 以 prevPos 和 二进制占位为key,只要二进制占位相同,数组长度也必然是相同的。
    String key = prevPos + "#" + u;
    if (memo.containsKey(key)) {
      return memo.get(key);
    }

    int res = 0;
    for(int i = 0; i < nums.length; i++) {
      if(!visited[i]) {
        if (prevPos == -1 || nums[prevPos] % nums[i] == 0 || nums[i] % nums[prevPos] == 0) {
          visited[i] = true;
          res = (res + dfs(nums, depth + 1, i, visited, u | (1 << i), memo)) % 1000000007;
          visited[i] = false;
        }
      }
    }
    memo.put(key, res);
    return res;
  }
}

🍻 位运算优化记忆化搜索

在这里插入图片描述

class Solution {

  public int specialPerm(int[] nums) {
    int n = nums.length;
    int[][] memo = new int[1 << nums.length][nums.length];
    for(int i = 0; i < 1 << nums.length; i++) {
      Arrays.fill(memo[i], -1);
    }
    return dfs(nums, 0, -1, memo);

  }
  // dfs(u, prePos) 定义为: 集合为u时,上一次选择的prePos时的特殊排列树目,prePos为-1代表第一次选择。
  private int dfs(int[] nums, int u, int prevPos, int[][] memo) {
    // 当集合为nums时,说明形成了特殊的排列
    // 注意 - 优先级 大于 <<,所以<<要上括号
    if(u == ((1 << nums.length) - 1)) {
      return 1;
    }
    // 以 prevPos 和 二进制占位为key,只要二进制占位相同,数组长度也必然是相同的。
    if (prevPos != -1 && memo[u][prevPos] != -1) {
      return memo[u][prevPos];
    }

    int res = 0;
    for(int i = 0; i < nums.length; i++) {
      // u >> i & 1 表明u向右移动i位,然后与1做与运算,等于1时表明i在集合u中,等于0则不在u中,代替了visited数组
      // i不在集合中,才继续遍历
      if((u >> i & 1) == 0) {
        if (prevPos == -1 || nums[prevPos] % nums[i] == 0 || nums[i] % nums[prevPos] == 0) {
          res = (res + dfs(nums, u | (1 << i),  i, memo)) % 1000000007;
        }
      }
    }

    if(prevPos == -1) {
      return res;
    }
    return memo[u][prevPos] = res;
  }
}

🍻 填表法 DP

在这里插入图片描述

class Solution {

  public int specialPerm(int[] nums) {
    int mod = (int) 1e9 + 7;
    int dp[][] = new int[1 << nums.length][nums.length ];
    // dp[u][j] := 当前集合为u,最后一次选择为j时的 特殊排列方案数 
    for (int i = 0; i < nums.length; i++) {
      // 选择i后,集合中增加i
      dp[1 << i][i] = 1;
    }

    for (int u = 0; u < 1 << nums.length; u++) {
      // 考虑当前集合为u时,加入新的数到集合中
      for (int j = 0; j < nums.length; j++) {
        // 集合u中不存在j时,j才能加入集合
        if ((u >> j & 1) == 0) {
          // 判断上一个选择的数k是否与j满足题意要求
          for (int k = 0; k < nums.length; k++) {
            // k不在集合中时 说明上一个数选择的数不可能是k
            if((u & 1 << k) > 0) {
              // k和j满足题意要求时才能形成特殊排列
              if ((nums[j] % nums[k] == 0 || nums[k] % nums[j] == 0)) {
                dp[u | 1 << j][j] = (dp[u | 1 << j][j] + dp[u][k]) % mod;
              }
            }
          }
        }
      }
    }

    int sum = 0;
    // 集合为nums,遍历最后一次选择的数
    for (int j = 0; j < nums.length; j++) {
      sum = (sum + dp[(1 << nums.length) - 1][j]) % mod;
    }

    return sum;
  }
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/747329.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Stm32的DMA的学习

一&#xff0c;介绍 二&#xff0c;DMA框图 三&#xff0c;DMA通道 四&#xff0c;相关HAL库函数 五&#xff0c;配置DMA 六&#xff0c;Stm32CubeMX配置 【13.1】减少CPU传输负载 DMA直接存储器访问—Kevin带你读《STM32Cube高效开发教程基础篇》_哔哩哔哩_bilibili

机票、火车票,YonSuite让企业支出笔笔可控

在数字化浪潮的推动下&#xff0c;企业的商旅管理正迎来一场深刻变革。传统的手动预订、报销模式已无法满足现代企业对效率和成本控制的双重要求。YonSuite商旅费控&#xff0c;作为一款领先的企业商旅管理平台&#xff0c;正以其独特的优势&#xff0c;帮助企业实现机票、火车…

【Android】多种方式实现截图(屏幕截图、View截图、长图)

目录 一、截图原理二、实现方式1. View截图2. WebView截图3. 屏幕截图 三、格式转换方法 一、截图原理 我们的手机一般同时按下音量-键和电源键就会将当前屏幕显示的内容截取下来&#xff0c;那里面具体经过哪些流程呢&#xff1f; Android中每一个页面都是一个Activity&#…

MySQL进阶_3.MySQL日志

文章目录 第一节、MySQL事务日志1.1、redo日志1.1.1、为什么需要REDO日志1.1.2、REDO日志的好处、特点1.1.3、redo的组成1.1.4、redo的整体流程 1.2、Undo日志1.2.1、如何理解Undo日志1.2.2、Undo日志的作用1.2.3、undo log的生命周期 第一节、MySQL事务日志 事务有4种特性&am…

Mybatis 系列全解(2)——全网免费最细最全,手把手教,学完就可做项目!

Mybatis 系列全解&#xff08;2&#xff09; 1. ResultMap结果集映射2. 日志2.1 日志工厂2.2 log4j 3. 分页3.1 实现SQL分页3.2 RowBounds 分页3.3 分页插件 4. 使用注解开发4.1 面向接口编程4.2 使用注解4.3 Mybatis 详细执行过程4.4 CRUD 增删改查 5. Lombok 1. ResultMap结果…

无人门店社区拼团小程序系统源码

​打造便捷购物新体验 &#x1f6d2; 引言&#xff1a;社区购物新趋势 随着科技的飞速发展&#xff0c;无人门店和社区拼团已经成为购物的新趋势。而结合这两者的“无人门店社区拼团微信小程序”更是为我们带来了前所未有的便捷购物体验。无需排队、无需现金交易&#xff0c;只…

营销能力大提升:6步策略助你成为市场精英

作为一名拥有9年经验的营销老兵&#xff0c;道叔有一些心得想要分享给每一位在营销领域奋斗的朋友。 在这个快速变化的行业里&#xff0c;除了掌握营销的专业知识&#xff0c;还有一些技能和视角是我们必须掌握的。 1. 培养业务视角 你有没有注意到&#xff0c;现在企业在投…

[word] 如何在word中插入地图? #学习方法#其他

如何在word中插入地图&#xff1f; 人事部门在给即将入职的新员工发送入职资料时&#xff0c;为了方便新员工能快速找到公司的具体位置&#xff0c;一般都会在word资料中插入公司所在位置的地图。今天&#xff0c;小编就分享一个在word中插入地图的方法。 第一步&#xff1a;…

Linux 扩容 根分区

CentOS7,LVM根分区扩容步骤: LVM扩容思维流程:创建一个物理分区–>将这个物理分区转换为物理卷–>把这个物理卷添加到要扩展的卷组中–>然后才能用extend命令扩展此卷组中的逻辑卷 1.查看现有分区大小 df -TH 2.关机增加大小为40G(测试环境使用的Vmware Workstati…

FPGA开发技能(7)Vivado设置bit文件加密

文章目录 前言1. AES加密原理2.xilinx的AES方案3.加密流程3.1生成加密的bit流3.2将密钥写入eFUSE寄存器 4.验证结论5.传送门 前言 在FPGA的项目发布的时候需要考虑项目工程加密的问题&#xff0c;一方面防止自己的心血被盗&#xff0c;另一方面也保护公司资产&#xff0c;保护知…

使用conda安装第三方包报错CondaSSLError

使用conda安装第三方包报错CondaSSLError 1. 报错信息2. 解决方法 1. 报错信息 错误描述&#xff1a;刚刚下载的 anaconda 在使用 conda 安装 pytorch 时报错&#xff08;CondaSSLError: OpenSSL appears to be unavailable on this machine. OpenSSL is required to download …

Python数据分析第一课:Anaconda的安装使用

Python数据分析第一课&#xff1a;Anaconda的安装使用 1.Anaconda是什么&#xff1f; Anaconda是一个便捷的获取包&#xff0c;并且对包和环境进行管理的虚拟环境工具,Anaconda包括了conda、Python在内的超过180多个包和依赖项 简单来说&#xff0c;Anaconda是包管理器和环境…

1变3裂变营销,七星创客模式,推三返一模式解析

推三返一模式的出现让我们看到&#xff0c;在商业竞争中&#xff0c;创新的商业模式与良好的产品服务相结合&#xff0c;才能真正赢得市场和消费者的心。 推三返一又称为“三三循环”模式&#xff0c;是一种简单粗暴的营销模式&#xff0c;消费者通过直接推荐三个新用户到平台消…

Java后端 || ElementUI 显示后端树形表格数据

文章目录 1、前端源码2、数据库设计3、后端设计3.1、实体类3.2、Controller层3.3、具体树形列表后端代码实现 1、前端源码 ElementUI Table 链接 在此链接中找到 树形数据与懒加载 查看其JS源码&#xff0c;可知&#xff0c;每个菜单节点的子节点存放于children字段中&#x…

天润融通助力立升净水,AI技术打造全天候智能客服体系

水&#xff0c;作为生命之源&#xff0c;其纯净度直接关系到人类的健康与社会的可持续发展。 在工业化和城市化进程的不断推进中&#xff0c;我们面临着土壤、空气等环境因素对饮用水质量的挑战。近期的公共卫生事件更是将饮用水安全问题推到了公众视野的中心&#xff0c;引发…

【论文阅读】-- Temporal Summary Images:通过交互式注释生成和放置实现叙事可视化的方法

Temporal Summary Images: An Approach to Narrative Visualization via Interactive Annotation Generation and Placement 摘要1 引言2 背景及相关工作2.1 叙事可视化和讲故事2.2 显示面向时间的数据2.3 小倍数和漫画2.4 注释可视化 3 设计要求和工作流程3.1 工作流程3.2 TSI…

科技未来·无限可能“2024世亚智博会”

随着科技的飞速发展&#xff0c;人类社会正以前所未有的速度迈向一个全新的时代。科学技术作为第一生产力&#xff0c;不仅极大地推动了经济和社会的发展&#xff0c;更在不断地改变着我们的生活方式和思维方式。特别是在人工智能、物联网等前沿科技领域&#xff0c;其创新和应…

搜索引擎的妙用:掌握这些技巧,让你的搜索更高效!

搜索引擎是我们日常生活中不可或缺的工具&#xff0c;它帮助我们快速找到所需的信息。但是&#xff0c;你真的知道如何高效地使用搜索引擎吗&#xff1f;下面&#xff0c;我将分享一些高级搜索技巧&#xff0c;让你的搜索更加精准和高效。 1. 完全匹配搜索 当你想要搜索一个特…

OutOfMemoryError能被catch(Exception)捕获吗?

背景 写了一个 Kafka 消费者程序&#xff0c;Kafka 集群中数据量过大时&#xff0c;消费线程无故退出了&#xff0c;日志打印了心跳 OOM 异常信息&#xff1a; 但是消费线程里面的 run 方法里面明明包含了 catch (Exception e) &#xff0c;结尾信息没有打印异常&#xff0c;…

钢筋计在工程项目中的关键应用与优势

在长期工程项目中&#xff0c;如大型桥梁、高层建筑或深基坑工程中&#xff0c;钢筋是承载结构的重要组成部分。为确保工程质量和安全&#xff0c;监测与管理钢筋的状态至关重要。钢筋计作为一种先进的监测工具&#xff0c;在长期工程项目中发挥着不可替代的作用。 1. 钢筋计的…