LeetCode题练习与总结:扰乱字符串--87

一、题目描述

使用下面描述的算法可以扰乱字符串 s 得到字符串 t

1. 如果字符串的长度为 1 ,算法停止

2. 如果字符串的长度 > 1 ,执行下述步骤:

  • 在一个随机下标处将字符串分割成两个非空的子字符串。即,如果已知字符串 s ,则可以将其分成两个子字符串 xy ,且满足 s = x + y
  • 随机 决定是要「交换两个子字符串」还是要「保持这两个子字符串的顺序不变」。即,在执行这一步骤之后,s 可能是 s = x + y 或者 s = y + x
  • xy 这两个子字符串上继续从步骤 1 开始递归执行此算法。

给你两个 长度相等 的字符串 s1 和 s2,判断 s2 是否是 s1 的扰乱字符串。如果是,返回 true ;否则,返回 false

示例 1:

输入:s1 = "great", s2 = "rgeat"
输出:true
解释:s1 上可能发生的一种情形是:
"great" --> "gr/eat" // 在一个随机下标处分割得到两个子字符串
"gr/eat" --> "gr/eat" // 随机决定:「保持这两个子字符串的顺序不变」
"gr/eat" --> "g/r / e/at" // 在子字符串上递归执行此算法。两个子字符串分别在随机下标处进行一轮分割
"g/r / e/at" --> "r/g / e/at" // 随机决定:第一组「交换两个子字符串」,第二组「保持这两个子字符串的顺序不变」
"r/g / e/at" --> "r/g / e/ a/t" // 继续递归执行此算法,将 "at" 分割得到 "a/t"
"r/g / e/ a/t" --> "r/g / e/ a/t" // 随机决定:「保持这两个子字符串的顺序不变」
算法终止,结果字符串和 s2 相同,都是 "rgeat"
这是一种能够扰乱 s1 得到 s2 的情形,可以认为 s2 是 s1 的扰乱字符串,返回 true

示例 2:

输入:s1 = "abcde", s2 = "caebd"
输出:false

示例 3:

输入:s1 = "a", s2 = "a"
输出:true

提示:

  • s1.length == s2.length
  • 1 <= s1.length <= 30
  • s1s2 由小写英文字母组成

二、解题思路

这个问题可以使用递归+记忆化搜索的方法解决。首先,判断两个字符串是否是扰乱字符串,需要满足以下条件:

  1. 两个字符串长度相等。
  2. 两个字符串包含的字符种类和数量相同。
  3. 存在一种方式,使得其中一个字符串可以通过一系列交换和分割操作变成另一个字符串。

基于这些条件,我们可以设计一个递归函数,该函数尝试对字符串进行分割,并判断左右两部分是否满足扰乱字符串的条件。为了提高效率,我们使用一个三维数组来存储已经计算过的结果,避免重复计算。

三、具体代码

class Solution {// 使用三维数组来记忆化搜索结果private boolean[][][] memo;public boolean isScramble(String s1, String s2) {if (s1 == null || s2 == null || s1.length() != s2.length()) {return false;}int len = s1.length();memo = new boolean[len][len][len + 1];return isScrambleHelper(s1, 0, s2, 0, len);}private boolean isScrambleHelper(String s1, int start1, String s2, int start2, int length) {// 如果记忆化数组中有结果,直接返回if (memo[start1][start2][length] == true) {return true;}// 如果两个子串相等,说明它们是扰乱字符串if (s1.substring(start1, start1 + length).equals(s2.substring(start2, start2 + length))) {memo[start1][start2][length] = true;return true;}// 检查两个子串的字符计数是否相同if (!checkCharacters(s1, start1, start1 + length, s2, start2, start2 + length)) {return false;}// 尝试所有可能的分割方式for (int i = 1; i < length; i++) {// 不交换的情况if (isScrambleHelper(s1, start1, s2, start2, i) &&isScrambleHelper(s1, start1 + i, s2, start2 + i, length - i)) {memo[start1][start2][length] = true;return true;}// 交换的情况if (isScrambleHelper(s1, start1, s2, start2 + length - i, i) &&isScrambleHelper(s1, start1 + i, s2, start2, length - i)) {memo[start1][start2][length] = true;return true;}}// 如果所有情况都不满足,返回falsereturn false;}// 检查两个子串的字符计数是否相同private boolean checkCharacters(String s1, int start1, int end1, String s2, int start2, int end2) {int[] count = new int[26];for (int i = start1; i < end1; i++) {count[s1.charAt(i) - 'a']++;}for (int i = start2; i < end2; i++) {count[s2.charAt(i) - 'a']--;}for (int c : count) {if (c != 0) {return false;}}return true;}
}

四、时间复杂度和空间复杂度

1. 时间复杂度
  • 对于长度为 n 的字符串,我们需要考虑所有可能的分割方式,这需要 O(n) 次迭代。
  • 对于每一种分割方式,我们需要递归地判断左右两部分是否是扰乱字符串。递归的深度最大为 n,因为每次递归都会将问题规模减半。
  • 在递归过程中,我们需要比较两个子串的字符计数是否相同,这个操作的时间复杂度是 O(n)
  • 综上所述,总的时间复杂度是 O(n * 2^(n-1)),因为对于每个长度为 n 的字符串,我们最多有 2^(n-1) 种分割方式,并且每次分割都需要 O(n) 的时间来比较字符计数。
2. 空间复杂度
  • 记忆化数组 memo 的大小是 n * n * (n+1),因此它的空间复杂度是 O(n^3)
  • 递归调用栈的最大深度是 n,因此它的空间复杂度是 O(n)
  • 因此,总的空间复杂度是 O(n^3),主要由记忆化数组 memo 占用。

五、总结知识点

  1. 递归算法:代码使用递归函数 isScrambleHelper 来解决问题。递归是一种常用的算法设计方法,它将问题分解为更小的子问题,并通过函数自身调用来解决这些子问题。

  2. 记忆化搜索:通过使用三维数组 memo 来存储已经计算过的结果,避免重复计算相同子问题,这是一种优化递归算法的技术,可以显著减少计算量。

  3. 字符串操作:代码中使用了 substring 方法来获取字符串的子串,以及 equals 方法来比较两个字符串是否相等。

  4. 字符计数:使用一个长度为 26 的整型数组 count 来计数两个子串中每个字符出现的次数,这是为了检查两个子串的字符组成是否相同。

  5. 动态规划思想:虽然代码是递归实现的,但它遵循了动态规划的原则,即通过解决重叠子问题并将结果存储起来,以达到优化计算的目的。

  6. 循环和条件判断:代码中使用了 for 循环来遍历所有可能的分割点,并使用了 if 语句来进行条件判断和分支选择。

  7. 算法设计:代码展现了如何设计一个算法来解决特定问题,即判断两个字符串是否为扰乱字符串。

  8. 边界条件处理:在 isScramble 方法中,首先检查了输入字符串是否为 null,长度是否相等,这些都是处理边界条件,确保输入有效。

以上就是解决这个问题的详细步骤,希望能够为各位提供启发和帮助。

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

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

相关文章

41.乐理基础-拍号-小节、小节线、终止线

小节线&#xff1a;下图红框中的竖线就是小节线 小节、终止线&#xff1a;最后的终止线就是文字意思表示乐谱结束了&#xff0c;后面没有了 下图中 0.5表示0.5拍&#xff08;八分音符&#xff09;、1表示1拍&#xff08;四分音符&#xff09;、0.25表示0.25拍&#xff08;十六分…

二、Redis五种常用数据类型-String

1、用途 简单的K-V缓存计数器分布式锁session共享分布式ID生成(自增) 2、底层实现结构 Redis底层是c语言实现的&#xff0c;但是并没有使用c的string来表示字符串&#xff0c;而是使用自己的简单动态字符串的抽象类型(simple dynamic string,SDS)。 SDS结构&#xff1a; st…

为什么centos官方版不支持arm架构?

为什么centos官方版不支持arm架构&#xff1f; 1、资源限制&#xff1a;CentOS是由社区维护的开源操作系统&#xff0c;其开发和维护需要大量的人力和物力资源。由于ARM架构的设备相对较少&#xff0c;社区资源有限&#xff0c;因此官方版CentOS选择集中精力在x86架构上进行开发…

编程基础学什么课程内容

编程基础学习的课程内容有&#xff1a;程序设计基础、算法与数据结构、计算机科学原理、面向对象编程、网页开发基础等课程内容&#xff0c;以下是上大学网 (www.sdaxue.com)整理的具体课程或技能领域内容&#xff0c;供大家参考&#xff01; 程序设计基础&#xff08;或计算机…

每日OJ题_DFS解决FloodFill⑦_力扣LCR 130. 衣橱整理(原剑指Offer13机器人的运动范围)

目录 力扣LCR 130. 衣橱整理&#xff08;原剑指Offer13机器人的运动范围&#xff09; 解析代码 力扣LCR 130. 衣橱整理&#xff08;原剑指Offer13机器人的运动范围&#xff09; LCR 130. 衣橱整理 难度 中等 家居整理师将待整理衣橱划分为 m x n 的二维矩阵 grid&#xff…

【精品毕设推荐】基于Javaee的影视创作论坛的设计与实现

点击下载原文及代码 摘 要 随着时代的发展&#xff0c;互联网的出现&#xff0c;给传统影视行业带来的最大便利就是&#xff0c;方便了影视从业人员以及爱好者的交流和互动&#xff0c;而为用户提供一个书写影评&#xff0c;阅读影评以及回复影评的平台&#xff0c;以影评为…

Spring MVC、Spring Boot和Spring Cloud 三者区别和联系

引言 近期在做系统重构的项目工作&#xff0c;在跟开发沟通对接过程中&#xff0c;经常听到他们讲开发框架&#xff1a;Spring MVC、Spring Boot、Spring Cloud&#xff0c;故对这三者进行一些学习了解&#xff0c;下面我针对由来、作用与关联等方面&#xff0c;来总结一下我学…

《第一行代码》第二版学习笔记(8)——网络技术

文章目录 一、Http1、HttpURLConnection2、OKHttp 二、解析JSON格式数据1、使用JSONObject2、使用GSON解析JSON数据 一、Http 1、HttpURLConnection public void run() {HttpURLConnection connection null;BufferedReader reader null;try {URL url new URL("http://…

力扣每日一题114:二叉树展开为链表

题目 中等 提示 给你二叉树的根结点 root &#xff0c;请你将它展开为一个单链表&#xff1a; 展开后的单链表应该同样使用 TreeNode &#xff0c;其中 right 子指针指向链表中下一个结点&#xff0c;而左子指针始终为 null 。展开后的单链表应该与二叉树 先序遍历 顺序相同…

js方法返回类型

在JavaScript中&#xff0c;方法可以是以下几种形式&#xff1a; 1. **函数声明**&#xff1a;传统的函数声明方式。 javascript function greet() { console.log(Hello, World!); } 2. **函数表达式**&#xff1a;使用变量赋值的方式定义函数。 javascript const greet…

2024年CMS市场的份额趋势和使用统计

目前市面上有超过一半的网站都是使用CMS来搭建的&#xff0c;据不完全统计&#xff0c;现在大概有900多种CDM可供选择&#xff0c;以下是最常见的CMS的市场份额和使用率信息&#xff1a; 除了WordPress以外&#xff0c;Shopify和Wix也是比较流行的内容管理系统&#xff0c;尤其…

239 基于matlab的EKF(扩展卡尔曼滤波)_UKF(无迹卡尔曼滤波)_PF(粒子滤波)三种算法的估计结果比较

基于matlab的EKF(扩展卡尔曼滤波)_UKF(无迹卡尔曼滤波)_PF&#xff08;粒子滤波&#xff09;三种算法的估计结果比较&#xff0c;输出估计误差&#xff0c;并单独对粒子滤波进行估计及其置信区间可视化。程序已调通&#xff0c;可直接运行。 239 EKF(扩展卡尔曼滤波) - 小红书 …

php 修改 文件权限 函数chmod()

目录 前言 前言 在PHP中&#xff0c;你可以使用chmod()函数修改文件的权限。该函数接受两个参数&#xff1a;文件路径和新的权限模式。以下是一个示例&#xff1a; php <?php // 文件路径 $filename example.txt;// 新的权限模式&#xff08;例如&#xff1a;0644&#…

一、Redis五种常用数据类型

Redis优势&#xff1a; 1、性能高—基于内存实现数据的存储 2、丰富的数据类型 5种常用&#xff0c;3种高级 3、原子—redis的所有单个操作都是原子性&#xff0c;即要么成功&#xff0c;要么失败。其多个操作也支持采用事务的方式实现原子性。 Redis特点&#xff1a; 1、支持…

【Linux】操作系统

上一篇博客我们从硬件的角度谈了计算机&#xff0c;我们说到了计算机的效率跟操作系统写的好不好有着直接的关系&#xff0c;那么这篇博客我们从软件的角度&#xff0c;就来谈一谈究竟什么是操作系统&#xff0c;为什么要有操作系统&#xff1f; 首先我们来大体的认识一下操作…

某塑料科技公司网络与机房监控运维项目

某塑料科技公司是由日本知名株式会社在中国投资的&#xff0c;以从事橡胶和塑料制品业为主的生产制造企业。随着企业信息化建设提速&#xff0c;信息化运用程度不断提高&#xff0c;对网络基础设施的管理也提出了更高要求&#xff0c;因此公司急需上线一款综合运维平台加强对整…

Go 语言 ORM 框架之 xorm

1、xorm 1.1、xorm 简介 xorm 是一个简单而强大的Go语言ORM库. 通过它可以使数据库操作非常简便。 特性 支持 struct 和数据库表之间的灵活映射&#xff0c;并支持自动同步事务支持同时支持原始SQL语句和ORM操作的混合执行使用连写来简化调用支持使用ID, In, Where, Limit,…

Linux—-vim基础使用

1、基本概念 Vim的工作模式有四种&#xff0c;普通模式&#xff0c;输入模式&#xff0c;命令模式&#xff0c;可视模式。 在终端中打开vim&#xff0c;只需要输入vim 文件&#xff0c;在普通模式下按i就会进入到输入模式&#xff0c;按下:进入命令模式&#xff0c;输入:q就可…

【前端学习——防抖和节流+案例】

定义 【前端八股文】节流和防抖 防抖 连续触发事件但是在设定的一段时间内只执行最后一次 代码实现思路【定时器】 大概意思就是&#xff1a; 每次按起键盘后&#xff0c;都将之前的定时器删除&#xff0c;重新开始计时。 节流 连续触发事件&#xff0c;只执行一次 …