【算法总结】——子集型回溯

news2025/1/11 2:16:47

文章目录

  • 子集型回溯
    • 例题1——78.子集
      • 代码模板1
      • 代码模板2
    • 例题2——131.分割回文串
      • 代码模板1
      • 代码模板2
      • 补充:怎么判断回文串
        • 双指针
        • dp提前处理
  • 参考资料

子集型回溯

在这里插入图片描述
主要学习 分别从 输入答案 去思考的两种代码模板。

例题1——78.子集

例题:78. 子集
在这里插入图片描述

代码模板1

站在 答案 的角度思考
枚举第一个数选谁
枚举第二个数选谁
每个节点都是答案

class Solution {
    List<List<Integer>> ans = new ArrayList();
    List<Integer> t = new ArrayList();

    public List<List<Integer>> subsets(int[] nums) {
        dfs(0, nums);
        return ans;
    }

    public void dfs(int startIndex, int[] nums) {
        ans.add(new ArrayList(t));
        if (startIndex == nums.length) {
            return;
        }
        for (int i = startIndex; i < nums.length; ++i) {
            t.add(nums[i]);
            dfs(i + 1, nums);
            t.remove(t.size() - 1);
        }
    }
}

代码模板2

站在 输入 的角度思考
每个数可以在子集中(选)
也可以不在子集中(不选)
叶子是答案

class Solution {
    List<List<Integer>> ans = new ArrayList();
    List<Integer> t = new ArrayList();

    public List<List<Integer>> subsets(int[] nums) {
        dfs(0, nums);
        return ans;
    }

    public void dfs(int i, int[] nums) {
        if (i == nums.length) {
            ans.add(new ArrayList(t));	// 当每个位置都经历了选和不选之后,加入答案
            return;
        }
        dfs(i + 1, nums);	// 不选直接下一个
        t.add(nums[i]);
        dfs(i + 1, nums);	// 选了之后递归下一个
        t.remove(t.size() - 1);
    }
}

个人感觉代码模板2更好理解一些。

例题2——131.分割回文串

https://leetcode.cn/problems/palindrome-partitioning/
在这里插入图片描述

所谓分割字符串,其实就是字符之间的逗号选不选的问题,因此这也是子集型回溯。

代码模板1

class Solution {
    boolean[][] st;
    List<List<String>> ans = new ArrayList();
    List<String> t = new ArrayList();

    public List<List<String>> partition(String s) {
        int n = s.length();
        st = new boolean[n][n];		// 提前计算出dp[i][j]表示从i~j是否为回文串
        for (int i = n - 1; i >= 0; --i) {
            for (int j = i; j < n; ++j) {
                if (i == j) st[i][j] = true;
                else if (j == i + 1) st[i][j] = s.charAt(i) == s.charAt(j);
                else st[i][j] = st[i + 1][j - 1] && s.charAt(i) == s.charAt(j);
            }
        }
        dfs(s, 0);
        return ans;
    }

    public void dfs(String s, int startIndex) {
        if (startIndex == s.length()) {
            ans.add(new ArrayList(t));
            return;
        }
        for (int i = startIndex; i < s.length(); ++i) {
            if (st[startIndex][i]) {	// 从startIndex到当前i是回文串
                t.add(s.substring(startIndex, i + 1));
                dfs(s, i + 1);
                t.remove(t.size() - 1);
            }
        }
    }
}

代码模板2

class Solution {
    List<List<String>> ans = new ArrayList();
    List<String> t = new ArrayList();

    public List<List<String>> partition(String s) {
        dfs(s, 0, 0);
        return ans;
    }

    public void dfs(String s, int i, int last) {
        if (i == s.length()) {	// 要选的字符已经选完了
            ans.add(new ArrayList(t));
            return;
        }
        if (i + 1 < s.length()) dfs(s, i + 1, last);	// 不选当前字符
        if (check(s, last, i)) {	// 如果当前字符可以被选择
            t.add(s.substring(last, i + 1));
            dfs(s, i + 1, i + 1);	// 由于当前字符要被选择了,所以下一个回文子串从i + 1开始
            t.remove(t.size() - 1);
        }
    }

    public boolean check(String s, int l, int r) {
        while (l < r) {
            if (s.charAt(l++) != s.charAt(r--)) return false;
        }
        return true;
    }
}

补充:怎么判断回文串

双指针

https://leetcode.cn/problems/find-first-palindromic-string-in-the-array/
两边各设置一个指针,分别为 l 和 r,逐步移动并比较是否相同。

或者叫 中心拓展法 ,从中间开始逐步向两边移动并比较。

class Solution {
public:
    string firstPalindrome(vector<string>& words) {
        // 判断字符串是否回文
        auto isPalindrome = [](const string& word) -> bool {
            int n = word.size();
            int l = 0, r = n - 1;
            while (l < r) {
                if (word[l] != word[r]) {
                    return false;
                }
                ++l;
                --r;
            }
            return true;
        };
        
        // 顺序遍历字符串数组,如果遇到回文字符串则返回,未遇到则返回空字符串
        for (const string& word: words) {
            if (isPalindrome(word)) {
                return word;
            }
        }
        return "";
    }
};

dp提前处理

https://leetcode.cn/problems/palindromic-substrings/

class Solution {
    public int countSubstrings(String s) {
        int n = s.length(), ans = 0;
        boolean[][] dp = new boolean[n][n];
        for (int i = n - 1; i >= 0; --i) {
            for (int j = i; j < n; ++j) {
                dp[i][j] = s.charAt(i) == s.charAt(j);
                if (j > i + 1) dp[i][j] &= dp[i + 1][j - 1];
                if (dp[i][j]) ++ans;
            }
        }
        return ans;
    }
}

提前处理的时间复杂度是 O(N^2),之后每次查询的时间复杂度是O(1).


参考资料

https://www.bilibili.com/video/BV1mG4y1A7Gu/

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

JavaSE基础语法--数组(1)

数组的定义与使用 数组就是存储相同数据类型的一组数据。它有如下特点&#xff1a; 1.数组中存放的数据是一样的 2.数组的空间是连续的 3.每个空间有自己的编号&#xff0c;其实位置的编号为0&#xff0c;即数组的下标 那么在Java里面如何定义一个数组呢&#xff1f; 假设…

【Python入门】Python循环语句(for循环的嵌套应用)

前言 &#x1f4d5;作者简介&#xff1a;热爱跑步的恒川&#xff0c;致力于C/C、Java、Python等多编程语言&#xff0c;热爱跑步&#xff0c;喜爱音乐的一位博主。 &#x1f4d7;本文收录于Python零基础入门系列&#xff0c;本专栏主要内容为Python基础语法、判断、循环语句、函…

行为型模式--中介者模式

目录 概述 结构 案例实现 优缺点 优点&#xff1a; 缺点&#xff1a; 使用场景 概述 一般来说&#xff0c;同事类之间的关系是比较复杂的&#xff0c;多个同事类之间互相关联时&#xff0c;他们之间的关系会呈现为复 杂的网状结构&#xff0c;这是一种过度耦合的架构&a…

深入理解深度学习——BERT派生模型:跨语言模型XLM(Cross-lingual Language Model)

分类目录&#xff1a;《深入理解深度学习》总目录 BERT本应在语义理解上具有绝对优势&#xff0c;但其训练语料均为英语单语&#xff0c;受限于此&#xff0c;早期的BERT只在英语文本理解上有优势。随着全球化进程的加速&#xff0c;跨语言的预训练语言模型也具有非常重要的应用…

seldom之数据驱动

seldom之数据驱动 如果自动化某个功能&#xff0c;测试数据不一样而操作步骤是一样的&#xff0c;那么就可以使用参数化来节省测试代码。 seldom是我在维护一个Web UI自动化测试框&#xff0c;这里跟大家分享seldom参数化的实现。 GitHub&#xff1a;GitHub - SeldomQA/seld…

idea设置项目编码为utf8

设置当前项目的编码为utf8 File -> Settings -> Editor -> File Encoding&#xff1a; 设置新建项目的编码为utf8 File -> New Projects Setup -> Settings for New Projects&#xff1a;

Flutter系列(九)ListView实现新闻列表和正文布局

基础工程&#xff1a; Flutter系列&#xff08;四&#xff09;底部导航顶部导航图文列表完整代码_摸金青年v的博客-CSDN博客 相关文章: Flutter系列&#xff08;七&#xff09;ListView 图文列表详解_flutter 图文列表_摸金青年v的博客-CSDN博客 一、前言 本文用flutter实现新闻…

注册 Google 邮箱(最新:保姆级教程)

文章目录 1、我们使用浏览器打开谷歌邮箱官网&#xff08;gmail.google.com&#xff09;&#xff0c;进入谷歌邮箱的登录主页&#xff0c;我们点击左下方的创建账号按钮&#xff0c;选择个人用途 2、在进入的界面我们不要着急填写资料&#xff0c;我们先修改语言&#xff0c;点…

(2023,3D 场景生成器 Infinigen)使用程序化生成的无限逼真世界

Infinite PhotorealisticWorlds using Procedural Generation 公众号&#xff1a;EDPJ 目录 0. 摘要 1. 简介 2. 相关工作 3. 方法 4. 实验 参考 S. 总结 S.1 主要思想 S.2 方法 S.3 场景生成 0. 摘要 我们介绍 Infinigen&#xff0c;一个自然世界逼真 3D 场景的…

Verilog | 除法--试商法

试商法 采用试商法实现除法运算&#xff0c;对于32位的除法&#xff0c;需要至少32个时钟周期才能得到除法结果。下面是试商法的一般过程。 设被除数是m&#xff0c;除数是n&#xff0c;商保存在s中&#xff0c;被除数的位数是k&#xff0c;其计算步骤如下&#xff08;为了便…

leetcode814. 二叉树剪枝(java)

二叉树剪枝 leetcode814. 二叉树剪枝题目描述DFS 深度优先遍历 二叉树专题 leetcode814. 二叉树剪枝 来源&#xff1a;力扣&#xff08;LeetCode&#xff09; 链接&#xff1a;https://leetcode.cn/problems/binary-tree-pruning 题目描述 给你二叉树的根结点 root &#xff0c…

《机器学习公式推导与代码实现》chapter17-kmeans

《机器学习公式推导与代码实现》学习笔记&#xff0c;记录一下自己的学习过程&#xff0c;详细的内容请大家购买作者的书籍查阅。 聚类分析和k均值聚类算法 聚类分析(cluster analysis)是一类经典的无监督学习算法&#xff0c;在给定样本的情况下&#xff0c;聚类分析通过度量…

【半监督:交叉分辨率:解纠缠】

Cross-Resolution Semi-Supervised Adversarial Learning for Pansharpening &#xff08;用于泛锐化的交叉分辨率半监督对抗学习&#xff09; 现有的基于深度神经网络&#xff08;DNN&#xff09;的方法已经产生了良好的泛锐化图像。然而&#xff0c;监督DNN为基础的泛锐化方…

卷积是什么

参考&#xff1a; 【官方双语】那么……什么是卷积&#xff1f;https://www.bilibili.com/video/BV1Vd4y1e7pj/ [建议看完] x.1 一维卷积 一维卷积&#xff0c;即对于两个向量的卷积&#xff0c;就是将向量翻转后&#xff0c;从前向后滑动&#xff0c;相乘再相加。 x.2 二维卷…

Spring Boot启动原理

Spring Boot的自动配置为我们提供了快捷方便的方式来运行Spring应用&#xff0c;但很多开发者对其内部启动原理还不是很明白。这篇博客旨在解开Spring Boot的神秘面纱&#xff0c;帮助大家理解它的启动原理。 入口类和注解 我们的Spring Boot应用通常从一个主类开始&#xff…

感知机(Perceptron)底层原理

1.感知机&#xff08;Perceptron&#xff09;底层原理 声明&#xff1a;笔记来源于《白话机器学习的数学》 感知机是接受多个输入后将每个值与各自权重相乘&#xff0c;最后输出总和的模型。 单层感知机因过于简单&#xff0c;无法应用于实际问题&#xff0c;但它是神经网络和深…

8个很少用,但却很好用的 Python 库!

本文介绍一些我们可能很少听过&#xff0c;但是对于特定问题或者特定任务来说&#xff0c;可能会非常有帮助的 Python 库 技术交流 技术要学会分享、交流&#xff0c;不建议闭门造车。一个人可以走的很快、一堆人可以走的更远。 好的文章离不开粉丝的分享、推荐&#xff0c;文…

黑马程序员前端 Vue3 小兔鲜电商项目——(六)二级分类页

文章目录 二级路由配置模版代码配置路由关系跳转配置 面包屑导航实现封装接口渲染数据 分类基础列表实现准备接口渲染数据 列表筛选实现无限加载实现定制路由 scrollBehavior 二级路由配置 模版代码 创建 src\views\SubCategory\index.vue 文件&#xff0c;添加以下代码&…

云服务器部署企业版openGauss,本地Data Studio远程连接

1.下载安装包 在华为云上租一台服务器&#xff0c;操作系统选&#xff1a;openEuler 20.03 64bit (64-bit) 获取openGauss Server安装包&#xff0c;企业版&#xff1a;软件包链接 使用xshell连接服务器&#xff0c;准备软硬件安装环境。准备软硬件安装环境 教程 下载Data …

javaee 过滤器加cookie实现自动登录

思路 如上图&#xff0c;如果勾选了自动登录&#xff0c;在登录时&#xff0c;就将用户名和密码存储到cookie中&#xff0c;当下次访问首页时&#xff0c;过滤器先拦截请求&#xff0c;获取下cookie中的账号密码&#xff0c;然后如果cookie中的账号密码有效就将登录信息存储到…