hot100 -- 回溯(下)

👂 ​​​​​​​▶ 幸福就是 (163.com)

👂 ▶ 当爱在靠近 (163.com)

目录

🚩括号生成

AC  DFS

🌼单词搜索

AC  DFS

🎂分割回文串

AC  DFS+DP

AC  DFS+记忆化

🌼N 皇后

AC  DFS


🚩括号生成

22. 括号生成 - 力扣(LeetCode)

AC  DFS

class Solution {
private:
    string temp; // 临时答案
    vector<string> ans;
    void dfs(int n, int l, int r) { // 左括号数 l, 右括号数 r
        // 递归出口
        if (temp.size() == 2*n) {
            ans.push_back(temp);
            return;
        }
        // 递归
        if (l < n) {
            temp.push_back('(');
            dfs(n, l + 1, r);
            temp.pop_back(); // 回溯时取消标记
        }
        if (r < l) { // 为了保证匹配,这里 r < l,保证左边的 '(' 匹配 右边的 ')'
            temp.push_back(')');
            dfs(n, l, r + 1);
            temp.pop_back();
        }
    }
public:
    vector<string> generateParenthesis(int n) {
        dfs(n, 0, 0);
        return ans;
    }
};

🌼单词搜索

79. 单词搜索 - 力扣(LeetCode)

AC  DFS

每个点 DFS 一次,有任一路径满足即可

class Solution {
private:
    int nex[4][2] = {{1,0},{-1,0},{0,1},{0,-1}}; // 4 个方向
    int vis[8][8];

    // (x, y) 开始, word 中第 count 个字符
    bool dfs(int x, int y, int count, vector<vector<char>>& board, string word) {
        int num = word.size(), m = board.size(), n = board[0].size();

        // 递归出口
        if (board[x][y] != word[count])
            return false;
        if (count == num - 1) 
            return true;
            
        vis[x][y] = 1; // 标记
        int result = 0;

        // 递归
        for (int i = 0; i < 4; ++i) {
            int xx = x + nex[i][0], yy = y + nex[i][1];
            if (xx >= 0 && xx < m && yy >= 0 && yy < n && !vis[xx][yy]) { // 未越界 && 未访问
                int flag = dfs(xx, yy, count + 1, board, word); // 递归   
                if (flag) {
                    result = 1;
                    break;
                }
            }
        }
        vis[x][y] = 0; // 取消标记
        return result;
    }
public:
    bool exist(vector<vector<char>>& board, string word) {
        int m = board.size(), n = board[0].size();
        // 从每一个点开始 DFS
        for (int i = 0; i < m; ++i) 
            for (int j = 0; j < n; ++j) {
                int flag = dfs(i, j, 0, board, word);
                if (flag) 
                    return true;
            }
        return false;
    }
};

🎂分割回文串

131. 分割回文串 - 力扣(LeetCode)

AC  DFS+DP

1)常规判断回文,用双指针 O(n),这里采用 DP O(1)👇

a. 含义:dp[i][j] == 1,字符串片段 [i, j] 是回文串

b. 递推式:dp[i][j] = s[i] == s[j] && dp[i + 1][j - 1]

c. 初始化:全部初始化为 1,两层 for 循环中,加个 s[i] == s[j] 的条件即可

d. 遍历顺序:根据递推式,且考虑到 i <= j,i 由 i + 1 得到,i 从 i = n - 1 开始遍历,j 从 i 开始

2)注意递归 dfs(s, j + 1),而不是 dfs(s, x + 1),因为当前 [x, j] 部分已经分割出来,并插入 temp 了,下一部分应该从 j + 1 开始 

 3)坑:第 33 行,dp 递推那里,j = i + 1 开始,否则当 i = 0, j = i = 0,此时 j - 1 == -1,会出现 dp[1][-1] 导致溢出

时间 O(n * 2^n)

O(n) 字符串长度

O(2^n) 长度为 n 的字符串划分方案数 2^(n-1) ≈ O(2^n)

class Solution {
private:
    vector<string> temp; // 临时答案
    vector<vector<string>> ans;
    vector<vector<int>> dp;
    int n; // 字符串 s 长度

    // 分割字串 [x, ...]
    void dfs(string s, int x) {
        // 递归出口:字符串末尾, 分割完毕
        if (x == n) {
            ans.push_back(temp);
            return;
        }
        // [x, x] ... [x, n-1]
        for (int j = x; j < n; ++j) {
            if (dp[x][j]) { // 回文
                temp.push_back(s.substr(x, j - x + 1));
                // [x, j] -> [j + 1, ...]
                // 递归分割下一部分
                dfs(s, j + 1);
                temp.pop_back(); // 回溯 恢复现场
            }
        }
    }
public:
    vector<vector<string>> partition(string s) {
        n = s.size();
        // 初始化 dp 为 1
        dp.resize(n, vector<int>(n, 1)); // 等价于 assign
        // dp 递归式
        for (int i = n - 1; i >= 0; --i)
            for (int j = i + 1; j < n; ++j) // j = i + 1 开始,防止 i = 0 时 溢出
                dp[i][j] = (s[i] == s[j]) && dp[i + 1][j - 1];

        dfs(s, 0); // 下标 0 开始分割 [0, ...]
        return ans; 
    }
};

AC  DFS+记忆化

将上面 O(1) 的 dp 变成 DFS 中的记忆化,本质一样,都是通过记录已有的结果,减少重复计算

记忆化一般用递归 return 实现

比 DP O(1) 求回文,慢很多

class Solution {
private:
    vector<string> temp; // 临时答案
    vector<vector<string>> ans;
    vector<vector<int>> dp;
    int n; // 字符串 s 长度

    // 分割字串 [x, ...]
    void dfs(string s, int x) {
        // 递归出口:字符串末尾, 分割完毕
        if (x == n) {
            ans.push_back(temp);
            return;
        }
        // [x, x] ... [x, n-1]
        for (int j = x; j < n; ++j) {
            if (isParlin(x, j, s) == 1) { // 回文
                temp.push_back(s.substr(x, j - x + 1));
                // [x, j] -> [j + 1, ...]
                // 递归分割下一部分
                dfs(s, j + 1);
                temp.pop_back(); // 回溯 恢复现场
            }
        }
    }
    // 记忆化搜索判断回文
    // 0 未搜索    1 回文    -1 非回文
    int isParlin(int l, int r, string s) {
        if (dp[l][r])
            return dp[l][r]; // 返回已有结果
        if (l >= r) 
            return dp[l][r] = 1; // 一个元素--回文

        return dp[l][r] = (s[l] == s[r]) ? isParlin(l+1, r-1, s) : -1;
    }
public:
    vector<vector<string>> partition(string s) {
        n = s.size();
        dp.resize(n, vector<int>(n)); // 初始化为 0

        dfs(s, 0); // 下标 0 开始分割 [0, ...]
        return ans; 
    }
};

🌼N 皇后

51. N 皇后 - 力扣(LeetCode)

AC  DFS

col[] 标记列,dfs(int r) 参数 r 标记行

两个点,行差值的绝对值 == 列差值的绝对值,表示(左斜 OR 右斜)冲突

由此,行,列,左斜,右斜是否冲突就可得到

取消标记时,只需要恢复 col[](对列的标记),而不需要恢复 a[](放置位置),因为 a[] 会被后续操作覆盖,但是 col 不会,需要手动恢复现场

坑:int flag = 0; 这个要放在 if(c[j] == 0) 里,如果放在外面,就算列已经被占了,也会进入下一步递归,平白多了许多无关结果 

class Solution {
private:
    vector<string> temp; // 临时答案
    vector<vector<string>> ans;
    int m;
    int c[10]; // 标记该列(已放置)
    int a[10]; // 位置, a[3] = 7 表示 (3, 7) 已放置

    // 第 r 行, 已放置 r 个皇后
    void dfs(int r) {
        // 递归出口
        if (r == m) {
            ans.push_back(temp);
            return;
        }
        // 遍历每一列
        for (int j = 0; j < m; ++j) {
            if (c[j] == 0) { // 这一列未放置
                int flag = 0; // 标记左斜 / 右斜 冲突

                for (int i = 0; i < r; ++i) // 遍历前面已放置的每一行
                    if (abs(r - i) == abs(j - a[i])) {
                        flag = 1;
                        break;
                    }
                // 不冲突,(r, j) 可以放置
                if (flag == 0) {
                    a[r] = j; // 放置

                    string s = string(m, '.');
                    s[j] = 'Q';
                    temp.push_back(s);

                    c[j] = 1; // 标记(列)
                    dfs(r + 1); 
                    c[j] = 0; // 取消标记
                    temp.pop_back(); // 恢复现场
                }
            }
        }
    }
public:
    vector<vector<string>> solveNQueens(int n) {
        m = n; // m 个皇后
        dfs(0);
        return ans;
    }
};

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

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

相关文章

TS38.300中的切换流程(很一般)

本文根据3GPP R18 TS 38.300第9.2.3节整理 切换(Handover)是移动终端(UE)进入RRC_CONNECTED状态后在不同服务小区(Cell)之间保持与网络联系唯一手段&#xff0c;期间首先通过控制面(C-Plane)进行无线测量、切换协商及触发等&#xff1b;为此3GPP在TS38.300中定义如下。 RAN系统…

Github 2024-05-31 Java开源项目日报 Top10

根据Github Trendings的统计,今日(2024-05-31统计)共有10个项目上榜。根据开发语言中项目的数量,汇总情况如下: 开发语言项目数量Java项目10TypeScript项目1JavaGuide - Java 程序员学习和面试指南 创建周期:2118 天开发语言:Java协议类型:Apache License 2.0Star数量:1…

IDEA 打开项目后看不到项目结构怎么办?

1、先把这个项目从 IDEA 中移除 2、再重新打开或导入 3、如果还没有解决&#xff0c;就先把这个项目拷贝出来把原来的路径上的项目给删除&#xff0c;然后再把拷贝后的项目放在一个路径下&#xff0c;再打开就可以了

C# 流程图demo

1、向panel添加控件。 2、panel控件中的控件可以自由拖动。 3、控件之间连线。 4、连线的控件&#xff0c;拖动时更新连线。 流程图连接线 //流程图连接线private void draggablePanel1_Paint(){Graphics g this.draggablePanel1.CreateGraphics();g.Clear(this.BackColor…

使用Python操作Git

大家好&#xff0c;当谈及版本控制系统时&#xff0c;Git是最为广泛使用的一种&#xff0c;而Python作为一门多用途的编程语言&#xff0c;在处理Git仓库时也展现了其强大的能力。通过Python&#xff0c;我们可以轻松地与Git仓库进行交互&#xff0c;执行各种操作&#xff0c;从…

leetcode148. 排序链表,归并法,分治的集大成之作

leetcode148. 排序链表 题目链接 给你链表的头结点 head &#xff0c;请将其按升序排列并返回排序后的链表。 示例 1&#xff1a; 输入&#xff1a;head [4,2,1,3] 输出&#xff1a;[1,2,3,4] 输入&#xff1a;head [-1,5,3,4,0] 输出&#xff1a;[-1,0,3,4,5] 示例 3&…

STM32 | 超声波实战

​01、上节回顾 STM32 | HC-SR04 超声波测距模块 | DHT11数字温湿度传感器(第七天)STM32 | 数字温湿度传感器DHT11STM32 | HC-SR04 超声波测距模块STM32 | DHT11数字温湿度传感器实战02、超声波图示 03、超声波头文件 #ifndef __SR04_H#define __SR04_H​#include "stm…

HNU-深度学习-电商多模态图文检索

前言 主要是跟着baseline搭了一遍&#xff0c;没有想到很好的优化。 有官方教程&#xff0c;但是有点谬误&#xff0c;所以就想着自己记录一下我的完成过程。 github项目地址&#xff1a; https://github.com/OFA-Sys/Chinese-CLIP 官方文档&#xff1a; 电商多模态图文检…

Django中使用Celery和APScheduler实现定时任务

在之前的文章我们已经学习了Celery和APScheduler的基本使用&#xff0c;下面让我们来了解一下如何在Django中使用Celery和APScheduler Celery 1.前提工作 python 3.7 pip install celery pip install eventlet #5.0版本以下 pip install importlib-metadata4.8.3&#xff08…

Git系列:rev-parse 使用技巧

&#x1f49d;&#x1f49d;&#x1f49d;欢迎莅临我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里可以感受到一份轻松愉快的氛围&#xff0c;不仅可以获得有趣的内容和知识&#xff0c;也可以畅所欲言、分享您的想法和见解。 推荐:「stormsha的主页」…

【机器学习300问】106、Inception网络结构如何设计的?这么设计的目的是什么?

谷歌的Inception网络&#xff0c;也被称为GoogLeNet&#xff0c;是Google在2014年推出的一种深度卷积神经网络&#xff08;CNN&#xff09;模型&#xff0c;在这之前的AlexNet、VGG等结构都是通过增大网络的深度&#xff08;层数&#xff09;来获得更好的训练效果&#xff0c;但…

车载监控解决方案在工程机械行业的应用

随着科技的快速发展&#xff0c;现代工程机械行业正迎来一场智能化、信息化的革命。GPS、4G通信、车载监控以及车载智能应用等技术的综合运用&#xff0c;为工程机械的安全作业提供了全方位、全时段的保障。本文以挖掘机为例&#xff0c;探讨车载监控解决方案在工程机械行业的广…

cleanmyMac有必要吗,什么软件可以替代clean my mac

最近总有苹果用户抱怨mac电脑变得非常卡顿&#xff0c;而且总会收到“您的启动磁盘几乎已经满了”的系统提示。提示出现的原因是我们长期未对电脑进行健康扫描和深度清理导致的。遇到这种情况&#xff0c;我们可以借助专业的电脑深度清理软件——CleanMyMac X&#xff0c;清理不…

漫画:什么是通用人工智能?

窄人工智能&#xff0c;对应英文Artificial Narrow Intelligence&#xff0c;简称ANI&#xff0c;也被称为特定任务人工智能。 顾名思义&#xff0c;窄人工智能用于完成某一项或几项特定的任务&#xff0c;比如智能驾驶、人脸识别、AlphaGo、AI绘画、大语言模型等等&#xff0c…

【Linux】Linux工具——yum,vim

1.Linux 软件包管理器——yum Linux安装软件&#xff1a; 源代码安装&#xff08;不建议&#xff09;rpm安装&#xff08;类似Linux安装包&#xff0c;版本可能不兼容&#xff0c;不推荐&#xff0c;容易报错&#xff09;yum安装&#xff08;解决了安装源&#xff0c;安装版本&…

FL Studio Producer Edition 21.2.3.4004全插件+Crack下载链接(亲测可用,非钓鱼)

FL Studio 21.2.3.4004中文版 中文别名水果编曲软件&#xff0c;是一款全能的音乐制作软件&#xff0c;包括编曲、录音、剪辑和混音等诸多功能&#xff0c;让你的电脑编程一个全能的录音室&#xff0c;它为您提供了一个集成的开发环境&#xff0c;使用起来非常简单有效&#xf…

Java实战:从文件读出学生列表

本实战项目的目标是从文本文件中读取学生列表&#xff0c;并验证读取过程的正确性通过单元测试。 创建静态方法 实现一个名为readStudentsFromFile的静态方法&#xff0c;该方法接收一个文件路径作为参数。创建一个Student对象的列表&#xff0c;用于存储从文件中读取的学生信息…

Java实战:将学生列表写入文件

本实战项目旨在演示如何使用Java语言将学生信息列表写入到一个文本文件中&#xff0c;并进行单元测试以确保代码的正确性。 创建静态方法 定义一个名为writeStudentsToFile的静态方法&#xff0c;该方法接收两个参数&#xff1a;一个Student对象的列表和一个文件路径。使用File…

Ultralytics x SwanLab:可视化YOLO模型训练

Ultralytics是YOLO官方团队推出的CV训练与推理框架&#xff0c;不仅支持目标检测任务&#xff0c;还支持分割、姿态识别、分类等更多任务。 SwanLab是一个深度学习实验管理与训练可视化工具&#xff0c;由西安电子科技大学团队打造&#xff0c;融合了Weights & Biases与Ten…

【协议开发系列】梳理关于TCP和UDP两种协议的区别和使用场景

起源 前二天项目上在核对外部对接服务的五元组列表的时候&#xff0c;有一位客户提问对于同样的服务同时支持tcp和udp二种方式&#xff0c;有什么优点和缺点&#xff0c;应该如何选择&#xff1f;这个问题突然让我愣了一下&#xff0c;确实好久没有“温故”了&#xff0c;相关…