力扣日记1.27-【回溯算法篇】131. 分割回文串

2024-01-28 17:36

本文主要是介绍力扣日记1.27-【回溯算法篇】131. 分割回文串,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

力扣日记:【回溯算法篇】131. 分割回文串

日期:2023.1.27
参考:代码随想录、力扣

131. 分割回文串

题目描述

难度:中等

给你一个字符串 s,请你将 s 分割成一些子串,使每个子串都是 回文串 。返回 s 所有可能的分割方案。

回文串 是正着读和反着读都一样的字符串。

示例 1:

输入:s = “aab”
输出:[[“a”,“a”,“b”],[“aa”,“b”]]

示例 2:

输入:s = “a”
输出:[[“a”]]

提示:

  • 1 <= s.length <= 16
  • s 仅由小写英文字母组成

题解

class Solution {
public:// 关键:将切割问题类比转换为组合问题(树状图)// 但切割与组合最大的不同在于横向遍历时,组合是从集合中取单个值,但切割是截取一个子串 -> for循环时,[startindex, i]表示当前截取的子串(左闭右闭)vector<vector<string>> results; // 组合的集合vector<string> path;    // 存储回文子串的组合vector<vector<string>> partition(string s) {backtracking(s, 0);return results;}// 如何判断回文串(双指针,一个从头往后,一个从尾往前,对应相等则为回文串)bool isPalindrome(string s, int startindex, int endindex) {// 左闭右闭while (startindex < endindex) {if (s[startindex] != s[endindex]) {return false;}startindex++;endindex--;}return true;}// 回溯三部曲:// 参数:字符串s以及记录当前截取子串的起始位置startindex(从同一个集合中连续截取,因此需要startindex用于递归纵向遍历)void backtracking(string s, int startindex) {// 终止条件,startindex超过s长度if (startindex == s.size()) { // 左闭,相等即超过// startindex能到最后,说明前面的子串都成功截取为回文串并保存了(否则在for循环将i遍历到最后return)results.push_back(path);return;}// for循环找到回文子串[startindex, i]for (int i = startindex; i < s.size(); i++) {// 是回文子串则截取并递归后面的子串,否则往后遍历找回文子串if (isPalindrome(s, startindex, i)) {// 截取子串并存储path.push_back(s.substr(startindex, i - startindex + 1)); // 注意substr的参数是起始位置以及截取长度backtracking(s, i + 1); // 从i之后的子串递归[i+1, s.size()-1]// 回溯,弹出path.pop_back(); // 之后for向右遍历,尝试截取[startindex, i+1]子串}}}};

复杂度

时间复杂度: O(n * 2^n)
空间复杂度: O(n^2)

思路总结

思路完全参考代码随想录

  • 本题实际上算是困难题目
  • 难点有以下:
    • 将切割问题抽象为组合问题,并转换为树状结构
    • 如何模拟那些切割线(如何记录截取子串的始末位置)
    • 切割问题中递归如何终止(终止条件)
    • 在递归循环中如何截取子串(什么时候该递归,什么时候跳过)
    • 如何判断回文
  • 将切割问题抽象为组合问题,并转换为树状结构:
    • 例如对于字符串abcdef:
      组合问题:选取一个a之后,在bcdef中再去选取第二个,选取b之后在cdef中再选取第三个…。
      切割问题:切割一个a之后,在bcdef中再去切割第二段,切割b之后在cdef中再切割第三段…。

    • 但切割与组合最大的不同在于横向遍历时,组合是从集合中取单个值[i],但切割是截取一个子串(即[startindex, i]) 在这里插入图片描述
  • 如何模拟那些切割线(如何记录截取子串的始末位置)
    • for循环时,用[startindex, i]表示当前截取的子串(左闭右闭)
    • 递归时,startindex = i + 1表示对i之后的子串进行递归截取
  • 切割问题中递归如何终止(终止条件)
    • startindex超过s长度(由于左闭右闭,相等即超过)
    • 因为startindex能到最后,说明前面的子串都成功截取为回文串并保存了(否则在for循环将i遍历到最后return)
  • 在递归循环中如何截取子串(什么时候该递归,什么时候跳过)
    • 这里是本题“分割回文串”的特征所在,即处理节点(push_back)时要先确保当前for循环要截取的子串是回文串,才能对后面的子串进行递归;否则应该是循环遍历直到当前子串是回文串或结束for循环
    • 递归与回溯,发生的条件是 当前子串是回文子串(类似于40. 组合总和 II中只有满足“当前取的值不重复”的条件才能递归是一样的。所以也可以写成
      for(...) {// 不是回文串则跳过if (!isPalindrome(...)) {continue;}// 递归与回溯...
      }
      
  • 如何判断回文子串:
    • 双指针法, 一个从头往后,一个从尾往前,对应相等则为回文串
  • TODO:动态规划优化判断回文子串

这篇关于力扣日记1.27-【回溯算法篇】131. 分割回文串的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!


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

相关文章

使用雪花算法产生id导致前端精度缺失问题解决方案

《使用雪花算法产生id导致前端精度缺失问题解决方案》雪花算法由Twitter提出,设计目的是生成唯一的、递增的ID,下面:本文主要介绍使用雪花算法产生id导致前端精度缺失问题的解决方案,文中通过代... 目录一、问题根源二、解决方案1. 全局配置Jackson序列化规则2. 实体类必须使用Long封装类3.

Springboot实现推荐系统的协同过滤算法

《Springboot实现推荐系统的协同过滤算法》协同过滤算法是一种在推荐系统中广泛使用的算法,用于预测用户对物品(如商品、电影、音乐等)的偏好,从而实现个性化推荐,下面给大家介绍Springboot... 目录前言基本原理 算法分类 计算方法应用场景 代码实现 前言协同过滤算法(Collaborativ

Python实现图片分割的多种方法总结

《Python实现图片分割的多种方法总结》图片分割是图像处理中的一个重要任务,它的目标是将图像划分为多个区域或者对象,本文为大家整理了一些常用的分割方法,大家可以根据需求自行选择... 目录1. 基于传统图像处理的分割方法(1) 使用固定阈值分割图片(2) 自适应阈值分割(3) 使用图像边缘检测分割(4)

Python如何将大TXT文件分割成4KB小文件

《Python如何将大TXT文件分割成4KB小文件》处理大文本文件是程序员经常遇到的挑战,特别是当我们需要把一个几百MB甚至几个GB的TXT文件分割成小块时,下面我们来聊聊如何用Python自动完成这... 目录为什么需要分割TXT文件基础版:按行分割进阶版:精确控制文件大小完美解决方案:支持UTF-8编码

openCV中KNN算法的实现

《openCV中KNN算法的实现》KNN算法是一种简单且常用的分类算法,本文主要介绍了openCV中KNN算法的实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的... 目录KNN算法流程使用OpenCV实现KNNOpenCV 是一个开源的跨平台计算机视觉库,它提供了各

springboot+dubbo实现时间轮算法

《springboot+dubbo实现时间轮算法》时间轮是一种高效利用线程资源进行批量化调度的算法,本文主要介绍了springboot+dubbo实现时间轮算法,文中通过示例代码介绍的非常详细,对大家... 目录前言一、参数说明二、具体实现1、HashedwheelTimer2、createWheel3、n

SpringBoot实现MD5加盐算法的示例代码

《SpringBoot实现MD5加盐算法的示例代码》加盐算法是一种用于增强密码安全性的技术,本文主要介绍了SpringBoot实现MD5加盐算法的示例代码,文中通过示例代码介绍的非常详细,对大家的学习... 目录一、什么是加盐算法二、如何实现加盐算法2.1 加盐算法代码实现2.2 注册页面中进行密码加盐2.

Java时间轮调度算法的代码实现

《Java时间轮调度算法的代码实现》时间轮是一种高效的定时调度算法,主要用于管理延时任务或周期性任务,它通过一个环形数组(时间轮)和指针来实现,将大量定时任务分摊到固定的时间槽中,极大地降低了时间复杂... 目录1、简述2、时间轮的原理3. 时间轮的实现步骤3.1 定义时间槽3.2 定义时间轮3.3 使用时

C++字符串提取和分割的多种方法

《C++字符串提取和分割的多种方法》在C++编程中,字符串处理是一个常见的任务,尤其是在需要从字符串中提取特定数据时,本文将详细探讨如何使用C++标准库中的工具来提取和分割字符串,并分析不同方法的适用... 目录1. 字符串提取的基本方法1.1 使用 std::istringstream 和 >> 操作符示

如何通过Golang的container/list实现LRU缓存算法

《如何通过Golang的container/list实现LRU缓存算法》文章介绍了Go语言中container/list包实现的双向链表,并探讨了如何使用链表实现LRU缓存,LRU缓存通过维护一个双向... 目录力扣:146. LRU 缓存主要结构 List 和 Element常用方法1. 初始化链表2.