学习记录:js算法(八十八):分割回文串

文章目录

    • 分割回文串
      • 思路一:回溯法
      • 思路二:动态规划
      • 方法三:记忆化搜索
      • 方法四:迭代法
      • 方法五:位运算

分割回文串

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

示例 1:
输入:s = "aab"
输出:[["a","a","b"],["aa","b"]]示例 2:
输入:s = "a"
输出:[["a"]]

思路一:回溯法

function isPalindrome(str) {let left = 0, right = str.length - 1;while (left < right) {if (str[left] !== str[right]) {return false;}left++;right--;}return true;
}function partition(s, start = 0, path = [], result = null) {if (result === null) {result = [];}if (start === s.length) {result.push([...path]);return result;}for (let i = start; i < s.length; i++) {if (isPalindrome(s.slice(start, i + 1))) {path.push(s.slice(start, i + 1));partition(s, i + 1, path, result);path.pop(); // 回溯}}return result;
}function partitionPalindromes(s) {return partition(s);
}

讲解
使用回溯结合简单的回文检测来解决

  1. 定义辅助函数 isPalindrome:
    ○ 这个函数用于判断一个字符串是否为回文串。
    ○ 使用两个指针分别从字符串的头部和尾部向中心移动并比较字符是否相等。
  2. 定义递归函数 partition:
    ○ 参数包括:
    ■ s: 原始输入字符串。
    ■ start: 当前处理的子串起始位置。
    ■ path: 用于存储当前递归路径上的回文子串。
    ■ result: 最终结果数组,用于收集所有满足条件的分割方案。
    ○ 终止条件:当 start 等于字符串长度时,将 path 加入到结果数组 result 中。
    ○ 递归逻辑:
    ■ 遍历从 start 到字符串末尾的所有位置 i。
    ■ 如果从 start 到 i 的子串是回文串,则将其加入到 path 中。
    ■ 对剩余的字符串(从 i+1 开始)继续执行相同的操作。
    ■ 在递归结束后,从 path 中移除刚刚添加的子串,进行回溯。
  3. 调用 partition 函数:
    ○ 在主函数 partitionPalindromes 中,直接调用 partition 函数,无需额外参数,因为默认值已经设置好。

思路二:动态规划

var partition = function (s) {const n = s.length;const dp = Array.from({ length: n }, () => Array(n).fill(false));const result = [];// 预处理回文for (let end = 0; end < n; end++) {for (let start = end; start >= 0; start--) {if (s[start] === s[end] && (end - start <= 2 || dp[start + 1][end - 1])) {dp[start][end] = true;}}}function backtrack(start, path) {if (start === n) {result.push([...path]);return;}for (let end = start; end < n; end++) {if (dp[start][end]) {path.push(s.slice(start, end + 1));backtrack(end + 1, path);path.pop();}}}backtrack(0, []);return result;
};

思路

  1. 使用动态规划预处理字符串中的所有回文子串,以便在生成分割方案时快速查找。
  2. 创建一个二维数组 dp,其中 dp[i][j] 表示从索引 i 到 j 的子串是否为回文。
  3. 先填充 dp 数组,然后使用回溯算法生成分割方案。

步骤

  1. 初始化一个二维数组 dp,并根据回文的定义填充它。
  2. 使用嵌套循环遍历字符串,标记所有的回文子串。
  3. 定义 backtrack 函数,使用 dp 数组来检查子串是否为回文。
  4. 当找到一个回文子串时,加入路径并继续递归,直到到达字符串末尾。

方法三:记忆化搜索

function isPalindrome(str) {return str === str.split('').reverse().join('');
}function partition(s) {const result = [];const memo = {};function backtrack(start, path) {if (start === s.length) {result.push([...path]);return;}for (let end = start + 1; end <= s.length; end++) {const substring = s.slice(start, end);if (memo[substring] === undefined) {memo[substring] = isPalindrome(substring);}if (memo[substring]) {path.push(substring);backtrack(end, path);path.pop();}}}backtrack(0, []);return result;
}

思路:

  1. 结合回溯法和记忆化搜索,避免重复计算回文检查。
  2. 使用一个缓存对象 memo 来存储已经检查过的子串的回文结果。

步骤:

  1. 定义 isPalindrome 函数来检查回文。
  2. 在 partition 函数中,定义 backtrack 函数,尝试每个可能的子串。
  3. 在检查子串是否为回文时,首先查看 memo 是否已有结果,如果没有,则进行检查并存储结果。
  4. 继续回溯,直到找到所有可能的分割方案。

方法四:迭代法

function partition(s) {const result = [];const stack = [[0, []]];while (stack.length) {const [start, path] = stack.pop();if (start === s.length) {result.push(path);continue;}for (let end = start + 1; end <= s.length; end++) {const substring = s.slice(start, end);if (substring === substring.split('').reverse().join('')) {stack.push([end, [...path, substring]]);}}}return result;
}

思路:

  1. 使用迭代而非递归来生成所有可能的分割方案。
  2. 使用栈来存储当前的起始位置和分割路径。

步骤:

  1. 初始化一个栈,并将起始位置和空路径压入栈中。
  2. 当栈不为空时,弹出栈顶元素。
  3. 如果当前起始位置等于字符串长度,则将当前路径添加到结果中。
  4. 遍历从当前起始位置到字符串末尾的所有可能子串,检查它们是否为回文。
  5. 如果是回文,则将其加入路径并将新的状态压入栈中。

方法五:位运算

function isPalindrome(str) {return str === str.split('').reverse().join('');
}function partition(s) {const n = s.length;const result = [];const totalCombinations = 1 << n; // 2^nfor (let i = 0; i < totalCombinations; i++) {const path = [];let lastIndex = 0;for (let j = 0; j < n; j++) {if (i & (1 << j)) {const substring = s.slice(lastIndex, j + 1);if (isPalindrome(substring)) {path.push(substring);lastIndex = j + 1;}}}if (lastIndex === n) {result.push(path);}}return result;
}

思路:

  1. 利用位运算生成所有可能的分割方案。
  2. 通过位掩码的方式来表示每个字符是否为分割点。

步骤:

  1. 计算字符串的总组合数(2^n)。
  2. 遍历所有组合,使用位运算来确定哪些字符是分割点。
  3. 对于每个组合,检查生成的子串是否为回文。
  4. 如果最后的分割方案有效(即所有字符都被处理),将其添加到结果中。

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

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

相关文章

FFmpeg —— 通过AES-CTR方式对视频加密解密(详细介绍通过FFmpeg指令、代码方式进行加密解码,附源码)

背景 这里使用ffmpeg通过AES-CTR加密方式对视频进行加密保存、解密播放。 1、纯指令方式(加密解密) 指令方式:对本地mp4文件加密后另存为mp4: # 使用AES-128-CBC算法对视频文件进行加密 ffmpeg -i xx.mp4 -c:v copy -c:a copy -encryption_scheme cenc-aes-ctr

Mac中禁用系统更新

Mac中禁用系统更新 文章目录 Mac中禁用系统更新1. 修改hosts&#xff0c;屏蔽系统更新检测联网1. 去除系统偏好设置--系统更新已有的小红点标记 1. 修改hosts&#xff0c;屏蔽系统更新检测联网 打开终端&#xff0c;执行命令&#xff1a; sudo vim /etc/hosts127.0.0.1 swdis…

Unity3D UI 双击和长按

Unity3D 实现 UI 元素双击和长按功能。 UI 双击和长按 上一篇文章实现了拖拽接口&#xff0c;这篇文章来实现 UI 的双击和长按。 双击 创建脚本 UIDoubleClick.cs&#xff0c;创建一个 Image&#xff0c;并把脚本挂载到它身上。 在脚本中&#xff0c;继承 IPointerClickHa…

sql专题 之 where和join on

文章目录 前言where介绍使用过滤结果集关联两个表 连接外连接内连接自然连接 使用inner join和直接使用where关联两个表的区别总结 前言 从数据库查询数据时&#xff0c;一张表不足以查询到我们想要的数据&#xff0c;更多的时候我们需要联表查询。 联表查询我们一般会使用连接…

LeetCode 热题100之 动态规划1

对于动态规划的问题&#xff0c;解题步骤有以下几部(总结为动态规划五部曲&#xff1a;参考代码随想录动态规划 确定dp数组以及下标的含义&#xff1b;确定递推公式&#xff1b;dp数组如何初始化&#xff1b;确定遍历顺序&#xff1b;举例推导dp数组 下面的解题思路分析都将从…

python可视化将多张图整合到一起(画布)

这周有点事忙着&#xff0c;没时间重温刚结束的Mathurcup数学建模&#xff0c;这两天也是再看了下&#xff0c;论文还是赶紧挺烂的&#xff0c;但比国赛又有进步&#xff08;说起国赛又不得不抱怨了&#xff0c;基本其余省份都发了&#xff0c;但江西......哎&#xff09;。哎&…

MFC图形函数学习07——画扇形函数

绘制扇形函数是MFC中绘图的基本函数&#xff0c;它绘制的仍是由椭圆弧与椭圆中心连线构成的椭圆扇形&#xff0c;特例是由圆弧与圆心连线构成的圆扇形。 一、绘制扇形函数 原型&#xff1a;BOOL Pie(int x1,int y1,int x2,int y2,int x3,int y3,int x4,int y4); …

vue 依赖注入(Provide、Inject )和混入(mixins)

Prop 逐级透传问题​ 通常情况下&#xff0c;当我们需要从父组件向子组件传递数据时&#xff0c;会使用 props。想象一下这样的结构&#xff1a;有一些多层级嵌套的组件&#xff0c;形成了一棵巨大的组件树&#xff0c;而某个深层的子组件需要一个较远的祖先组件中的部分数据。…

c++零基础入门知识点

名字空间&#xff08;namespace)的引入和使用 名字空间域是随标准C而引入的。它相当于一个更加灵活的文件域&#xff08;全局域&#xff09;&#xff0c;可以用花括号把文件的一部分括起来&#xff0c;并以关键字namespace开头给它起一个名字 //TestMain.cpp //1. 普通的命名空…

手机上用什么方法可以切换ip

手机上用什么方法可以切换IP&#xff1f;在某些特定情境下&#xff0c;用户可能需要切换手机的IP地址&#xff0c;以满足网络安全、隐私保护或绕过地域限制等需求。下面以华为手机为例&#xff0c;将详细介绍手机IP地址切换的几种方法&#xff0c;帮助用户轻松实现这一目标。 一…

全面解析 Python typing模块与静态类型注解:从基础到高级

在现代软件开发中&#xff0c;代码的可读性、维护性和可靠性至关重要。Python 作为一门动态类型语言&#xff0c;尽管灵活&#xff0c;但也可能带来一些类型上的困扰。Python 的 typing 模块和静态类型注解提供了一种在编写代码时明确类型信息的方法&#xff0c;从而提升代码质…

一个强大的Stable Diffusion comfyUI 工作流,能实现写真自由、各种风格融合、面部特征一致性等等

今天&#xff0c;我们将向您介绍一款非常实用的工具——Stable Diffusion comfyUI工作流。这款工作流基于Stable Diffusion技术&#xff0c;旨在为您提供一键式生成图像的便捷体验。无论您是AI绘画的新手还是专业人士&#xff0c;这个工作流都能为您带来极大的便利。 在这个教…

【测试】【Debug】pytest运行后print没有输出

import pytest def test_good():for i in range(1000):print(i)def test_bad():print(this should fail!)assert False比如上述程序&#xff0c;运行之后只能看到输出了’this should fail!&#xff1b;但是debug版的测试运行后又能看到test_good函数中的输出。 这是为什么呢&a…

外泌体相关基因肝癌临床模型预测——2-3分纯生信文章复现——6.外泌体基因功能注释(二)

内容如下: 1.外泌体和肝癌TCGA数据下载 2.数据格式整理 3.差异表达基因筛选 4.预后相关外泌体基因确定 5.拷贝数变异及突变图谱 6.外泌体基因功能注释 7.LASSO回归筛选外泌体预后模型 8.预后模型验证 9.预后模型鲁棒性分析 10.独立预后因素分析及与临床的相关性分析…

【Homework】【1--4】Learning resources for DQ Robotics in MATLAB

Learning resources for DQ Robotics in MATLAB Lesson 1 代码 % Step 2: Define the real numbers a1 and a2 a1 123; a2 321;% Step 3: Calculate and display a3 a1 a2 a3 a1 a2; disp([a3 (a1 a2) , num2str(a3)])% Step 4: Calculate and display a3 a1 * a2 a3…

ORACLE RAC用DNS服务器的配置

一、搭建本地YUM源 二、安装DNS全部组建 yum -y install bind* 三、规划您RAC集群所有IP #public 192.168.16.111 rac1.ntt.com rac1 192.168.16.112 rac2.ntt.com rac2 192.168.16.121 rac3.ntt.com rac3 192.168.16.122 rac4.ntt.com rac4 #private 10.10.10.111 rac1-pr…

Redis穿透、击穿、雪崩

redis是一款常用的非关系型数据库&#xff0c;我们常用与作为数据缓存的组件。 接下来介绍一下面试中常被问到的三个概念以及简单的解决方法。 穿透 什么叫缓存穿透 缓冲穿透&#xff0c;是当有一个请求过来时&#xff0c;查询redis缓存不存在&#xff0c;又去查询数据库&…

前向-后向卡尔曼滤波器(Forward-Backward Kalman Filter)资料汇总

《卡尔曼滤波引出的RTS平滑》参考位置2《卡尔曼滤波系列——&#xff08;六&#xff09;卡尔曼平滑》《关于卡尔曼滤波和卡尔曼平滑关系的理解》——有m语言例程《Forward Backwards Kalman Filter》——Matlab软件《卡尔曼滤波与隐马尔可夫模型》

linux命令详解,存储管理相关

存储管理 一、内存使用量&#xff0c;free free 命令是一个用于显示系统中物理内存&#xff08;RAM&#xff09;和交换空间&#xff08;swap&#xff09;使用情况的工具 free -m free -m -s 5参数 -b 功能: 以字节&#xff08;bytes&#xff09;为单位显示内存使用情况。说…

PHP API的路由设计思路

PHP API的路由设计是构建高效、可维护API的关键环节。以下是一套完整的PHP API路由设计思路&#xff1a; 一、明确设计原则 使用统一资源标识符&#xff08;URI&#xff09;&#xff1a;通过URI来标识资源&#xff0c;确保每个资源都有一个唯一的地址。使用HTTP方法&#xff…