算法leetcode|87. 扰乱字符串(rust重拳出击)

这篇具有很好参考价值的文章主要介绍了算法leetcode|87. 扰乱字符串(rust重拳出击)。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。



87. 扰乱字符串:

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

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

给你两个 长度相等 的字符串 s1s2,判断 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 由小写英文字母组成

分析:

  • 面对这道算法题目,二当家的再次陷入了沉思。
  • 我们并不知道分割点在哪里,所以需要枚举每一个位置。
  • 分割之后会发现,两两子串变成了规模较小的相同子问题,使用递归比较直观易理解。
  • 在不断枚举子串的过程中,会有重复判断的情况,这时候增加记忆,将中间处理结果保存下来是提高效率的关键。
  • 在枚举分割点的时候,要考虑交换位置的问题,两个字符串被分别分割为左右两个子串,除了要判断左左,右右子串是否匹配,还需要判断左右,右左是否匹配。

题解:

rust:

impl Solution {
    pub fn is_scramble(s1: String, s2: String) -> bool {
        fn dfs(s1: &[u8], s2: &[u8], memo: &mut Vec<Vec<Vec<i32>>>, i1: usize, i2: usize, length: usize) -> bool {
            if memo[i1][i2][length] != 0 {
                // 已经处理过,直接返回
                return memo[i1][i2][length] == 1;
            }

            // 判断两个子串是否相等
            let mut l = 0;
            while l < length && s1[i1 + l] == s2[i2 + l] {
                l += 1;
            }
            if l == length {
                memo[i1][i2][length] = 1;
                return true;
            }

            // 枚举分割位置
            for i in 1.max(l)..length {
                // 不交换的情况
                if dfs(s1, s2, memo, i1, i2, i) && dfs(s1, s2, memo, i1 + i, i2 + i, length - i) {
                    memo[i1][i2][length] = 1;
                    return true;
                }
                // 交换的情况
                if dfs(s1, s2, memo, i1, i2 + length - i, i) && dfs(s1, s2, memo, i1 + i, i2, length - i) {
                    memo[i1][i2][length] = 1;
                    return true;
                }
            }

            memo[i1][i2][length] = -1;
            return false;
        }

        let length = s1.len();
        dfs(s1.as_bytes(), s2.as_bytes(), &mut vec![vec![vec![0; length + 1]; length]; length], 0, 0, length)
    }
}

go:

func isScramble(s1 string, s2 string) bool {
    n := len(s1)
	memo := make([][][]int8, n)
	for i := range memo {
		memo[i] = make([][]int8, n)
		for j := range memo[i] {
			memo[i][j] = make([]int8, n+1)
		}
	}

	var dfs func(i1, i2, length int) bool
	dfs = func(i1, i2, length int) bool {
		if memo[i1][i2][length] != 0 {
			return memo[i1][i2][length] == 1
		}

		// 判断两个子串是否相等
		if s1[i1:i1+length] == s2[i2:i2+length] {
			memo[i1][i2][length] = 1
			return true
		}

		// 枚举分割位置
		for i := 1; i < length; i++ {
			// 不交换的情况
			if dfs(i1, i2, i) && dfs(i1+i, i2+i, length-i) {
				memo[i1][i2][length] = 1
				return true
			}
			// 交换的情况
			if dfs(i1, i2+length-i, i) && dfs(i1+i, i2, length-i) {
				memo[i1][i2][length] = 1
				return true
			}
		}

		memo[i1][i2][length] = -1
		return false
	}

	return dfs(0, 0, n)
}

c++:

class Solution {
private:
    // 第一个字符串从 i1 开始,第二个字符串从 i2 开始,子串的长度为 length,是否和谐
    bool dfs(string &s1, string &s2, vector<vector<vector<int>>> &memo, int i1, int i2, int length) {
        if (memo[i1][i2][length]) {
            return memo[i1][i2][length] == 1;
        }

        // 判断两个子串是否相等
        if (s1.substr(i1, length) == s2.substr(i2, length)) {
            memo[i1][i2][length] = 1;
            return true;
        }

        // 枚举分割位置
        for (int i = 1; i < length; ++i) {
            // 不交换的情况
            if (dfs(s1, s2, memo, i1, i2, i) && dfs(s1, s2, memo, i1 + i, i2 + i, length - i)) {
                memo[i1][i2][length] = 1;
                return true;
            }
            // 交换的情况
            if (dfs(s1, s2, memo, i1, i2 + length - i, i) && dfs(s1, s2, memo, i1 + i, i2, length - i)) {
                memo[i1][i2][length] = 1;
                return true;
            }
        }

        memo[i1][i2][length] = -1;
        return false;
    }
public:
    bool isScramble(string s1, string s2) {
        int length = s1.length();
        vector<vector<vector<int>>> memo(length, vector<vector<int>>(length, vector<int>(length + 1, 0)));
        return dfs(s1, s2, memo, 0, 0, length);
    }
};

python:

class Solution:
    def isScramble(self, s1: str, s2: str) -> bool:
        @cache
        def dfs(i1: int, i2: int, length: int) -> bool:
            """
            第一个字符串从 i1 开始,第二个字符串从 i2 开始,子串的长度为 length,是否和谐
            """

            # 判断两个子串是否相等
            if s1[i1:i1 + length] == s2[i2:i2 + length]:
                return True

            # 枚举分割位置
            for i in range(1, length):
                # 不交换的情况
                if dfs(i1, i2, i) and dfs(i1 + i, i2 + i, length - i):
                    return True
                # 交换的情况
                if dfs(i1, i2 + length - i, i) and dfs(i1 + i, i2, length - i):
                    return True

            return False

        ans = dfs(0, 0, len(s1))
        dfs.cache_clear()
        return ans


java:

class Solution {
    public boolean isScramble(String s1, String s2) {
        int length = s1.length();
        return dfs(s1.toCharArray(), s2.toCharArray(), new int[length][length][length + 1], 0, 0, length);
    }

    private boolean dfs(char[] s1, char[] s2, int[][][] memo, int i1, int i2, int length) {
        if (memo[i1][i2][length] != 0) {
            // 已经处理过,直接返回
            return memo[i1][i2][length] == 1;
        }

        // 判断两个子串是否相等
        int l = 0;
        while (l < length && s1[i1 + l] == s2[i2 + l]) {
            ++l;
        }
        if (l == length) {
            memo[i1][i2][length] = 1;
            return true;
        }

        // 枚举分割位置
        for (int i = Math.max(1, l); i < length; ++i) {
            // 不交换的情况
            if (dfs(s1, s2, memo, i1, i2, i) && dfs(s1, s2, memo, i1 + i, i2 + i, length - i)) {
                memo[i1][i2][length] = 1;
                return true;
            }
            // 交换的情况
            if (dfs(s1, s2, memo, i1, i2 + length - i, i) && dfs(s1, s2, memo, i1 + i, i2, length - i)) {
                memo[i1][i2][length] = 1;
                return true;
            }
        }

        memo[i1][i2][length] = -1;
        return false;
    }
}

非常感谢你阅读本文~
欢迎【点赞】【收藏】【评论】三连走一波~
放弃不难,但坚持一定很酷~
希望我们大家都能每天进步一点点~
本文由 二当家的白帽子:https://le-yi.blog.csdn.net/ 博客原创~文章来源地址https://www.toymoban.com/news/detail-745607.html


到了这里,关于算法leetcode|87. 扰乱字符串(rust重拳出击)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 【经典面试】87 字符串解码

    给定一个经过编码的字符串,返回它解码后的字符串。 编码规则为: k[encoded_string] ,表示其中方括号内部的 encoded_string 正好重复 k 次。注意 k 保证为正整数。 你可以认为输入字符串总是有效的;输入字符串中没有额外的空格,且输入的方括号总是符合格式要求的。 此外,你

    2024年02月08日
    浏览(45)
  • 算法学习——LeetCode力扣字符串篇

    344. 反转字符串 - 力扣(LeetCode) 描述 编写一个函数,其作用是将输入的字符串反转过来。输入字符串以字符数组 s 的形式给出。 不要给另外的数组分配额外的空间,你必须原地修改输入数组、使用 O(1) 的额外空间解决这一问题。 示例 示例 1: 输入:s = [“h”,“e”,“l”

    2024年02月20日
    浏览(44)
  • 数据结构与算法之字符串: Leetcode 557. 反转字符串中的单词 III (Typescript版)

    翻转字符串中的单词 III https://leetcode.cn/problems/reverse-words-in-a-string-iii/ 描述 给定一个字符串 s ,你需要反转字符串中每个单词的字符顺序,同时仍保留空格和单词的初始顺序。 示例 1: 示例 2: 提示: 1 = s.length = 5 * 1 0 4 10^4 1 0 4 s 包含可打印的 ASCII 字符。 s 不包含任何开头或

    2024年02月01日
    浏览(77)
  • LeetCode:459. 重复的子字符串 —【2、KMP算法】

    🍎道阻且长,行则将至。🍓 🌻算法,不如说它是一种思考方式🍀 算法专栏: 👉🏻123 题目描述 :给定一个非空的字符串 s ,检查是否可以通过由它的一个子串重复多次构成。 来源:力扣(LeetCode) 难度: 简单 提示: 1 = s.length = 104 s 由小写英文字母组成 示例 1: 输入:

    2024年02月04日
    浏览(82)
  • 代码随想录 Leetcode459. 重复的子字符串(KMP算法)

            此解法读者需要了解什么是KMP算法以及KMP算法中next数组的具体含义才能理解         因为在KMP算法的next数组中,next[index]表示 i ndex之前的最大长度的相同前缀后缀值 ,那么要判断整个字符串中是否由重复字串构成,只需要以下两个条件:         1.next[n - 1] !=

    2024年01月19日
    浏览(78)
  • 【编码狂想】LeetCode 字符串和数组篇:挑战算法精髓,深化程序设计基础

    ​ 🌈 个人主页: Sarapines Programmer  🔥 系列专栏: 本期文章收录在《C语言闯关笔记》,大家有兴趣可以浏览和关注,后面将会有更多精彩内容!  ⏰翰墨致赠:翩翩风华激彩虹,豪情壮志醉长空。 剑指星河舞红尘,梦驰烈马向未来。 ​ ​ 🎉欢迎大家关注🔍点赞👍收藏

    2024年02月04日
    浏览(51)
  • 数据结构与算法之字符串: Leetcode 20. 有效的括号 (Typescript版)

    有效的括号 https://leetcode.cn/problems/valid-parentheses/ 描述 给定一个只包括 ‘(’,‘)’,‘{’,‘}’,‘[’,‘]’ 的字符串 s ,判断字符串是否有效。 有效字符串需满足: 左括号必须用相同类型的右括号闭合。 左括号必须以正确的顺序闭合。 每个右括号都有一个对应的相

    2024年02月01日
    浏览(54)
  • 算法leetcode|66. 加一(rust重拳出击)

    给定一个由 整数 组成的 非空 数组所表示的非负整数,在该数的基础上加一。 最高位数字存放在数组的首位, 数组中每个元素只存储 单个 数字。 你可以假设除了整数 0 之外,这个整数不会以零开头。 1 = digits.length = 100 0 = digits[i] = 9 面对这道算法题目,二当家的再次陷入了

    2024年02月14日
    浏览(39)
  • 算法leetcode|79. 单词搜索(rust重拳出击)

    给定一个 m x n 二维字符网格 board 和一个字符串单词 word 。如果 word 存在于网格中,返回 true ;否则,返回 false 。 单词必须按照字母顺序,通过相邻的单元格内的字母构成,其中“相邻”单元格是那些水平相邻或垂直相邻的单元格。同一个单元格内的字母不允许被重复使用。

    2024年02月09日
    浏览(59)
  • 算法leetcode|65. 有效数字(rust重拳出击)

    有效数字 (按顺序)可以分成以下几个部分: 一个 小数 或者 整数 (可选)一个 \\\'e\\\' 或 \\\'E\\\' ,后面跟着一个 整数 小数 (按顺序)可以分成以下几个部分: (可选)一个符号字符( \\\'+\\\' 或 \\\'-\\\' ) 下述格式之一: 至少一位数字,后面跟着一个点 \\\'.\\\' 至少一位数字,后面跟着一个

    2024年02月15日
    浏览(45)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包