首页 > 其他分享 >小U的好字符串

小U的好字符串

时间:2024-12-25 12:31:59浏览次数:6  
标签:子串 字符 int 序列 字符串 回文

问题描述

小U定义了一个“好字符串”,它的要求是该字符串中不包含任意长度不小于2的回文子串。现在小U拿到了一个字符串,她想知道有多少个非空的子序列是“好字符串”。你的任务是帮助她计算出这些子序列的数量。

例如,对于字符串 "aba",它的子序列中除了 "aa" 和 "aba" 以外,其余五个子序列都是“好字符串”。

注意:由于答案可能非常大,你需要对结果取 10^9+7进行输出。


测试样例

样例1:

输入:s = "aba"
输出:5

样例2:

输入:s = "aaa"
输出:3

样例3:

输入:s = "ghij"
输出:15

C++解题

理解问题

  • 回文子串:一个字符串如果从左到右读和从右到左读是一样的,那么它就是回文子串。例如,"aba" 和 "aa" 都是回文子串。
  • 好字符串:一个字符串如果不包含任何长度不小于2的回文子串,那么它就是好字符串。

数据结构的选择

  • 我们可以使用动态规划(DP)来解决这个问题。动态规划可以帮助我们有效地计算出所有可能的子序列,并判断它们是否是好字符串

算法步骤

  1. 定义状态

    • 设 dp[i][j] 表示以字符 s[i] 结尾且长度为 j 的子序列是否是好字符串。
    • 初始状态:dp[i][1] = true 对于所有 i,因为单个字符总是好字符串。
  2. 状态转移

    • 对于每个字符 s[i],我们需要检查所有可能的子序列长度 j(从2开始)。
    • 如果 s[i] 和 s[i-1] 相同,那么 dp[i][2] = false,因为 "aa" 是回文子串。
    • 对于长度大于2的子序列,我们需要检查 dp[i-1][j-1] 是否为 true,并且 s[i] 不与前面的字符形成回文子串。
  3. 计算结果

    • 最终结果是所有 dp[i][j] 为 true 的子序列的数量之和。

关键步骤解释

  1. 初始化

    • 我们使用一个二维数组 f,其中 f[i][j] 表示以字符 i 结尾且长度为 j 的子序列的数量。
    • 初始化所有元素为 0
  2. 状态转移

    • 对于每个字符 ch,我们更新 f 数组。
    • 如果当前字符 x 与之前的字符 i 和 j 不同,则更新 f[j][x]
    • 如果 f[j][x] 超过 MOD,则取模。
  3. 计算结果

    • 遍历 f 数组,统计所有子序列的数量,并对结果取模 10^9 + 7

代码实现

#include <iostream>
#include <vector>
#include <string>

using namespace std;

const int MOD = 1e9 + 7;

int solution(const string& s) {
    int m = 26;
    vector<vector<int>> f(m + 1, vector<int>(m, 0));
    for (char ch : s) {
        int x = ch - 'a';
        for (int i = 0; i <= m; ++i) {
            if (i != x) {
                for (int j = 0; j < m; ++j) {
                    if (j != x) {
                        f[j][x] += f[i][j];
                        if (f[j][x] >= MOD) {
                            f[j][x] -= MOD;
                        }
                    }
                }
            }
        }
        f[m][x] += 1;
    }
    int ans = 0;
    for (int j = 0; j < m; ++j) {
        for (int i = 0; i <= m; ++i) {
            ans = (ans + f[i][j]) % MOD;
        }
    }
    return ans;
}

int main() {
    cout << (solution("aba") == 5) << endl;
    cout << (solution("aaa") == 3) << endl;
    cout << (solution("ghij") == 15) << endl;
    return 0;
}

Python解题

思路说明

题目要求计算一个字符串中所有不包含任意长度不小于2的回文子串的非空子序列的数量。核心在于如何判断一个子序列是否包含长度不小于2的回文子串。通过动态规划的方法,我们可以记录每个字符作为子序列结尾时,前一个字符的分布情况,从而避免生成回文子串。

解题过程

  1. 初始化动态规划数组

    • 使用一个二维数组 f,其中 f[i][j] 表示以字符 j 结尾且前一个字符为 i 的子序列数量。
    • f[m][x] 表示以字符 x 结尾且前一个字符为任意字符的子序列数量。
  2. 遍历字符串

    • 对于每个字符 ch,计算其对应的索引 x
    • 更新动态规划数组 f,确保不生成回文子串。
  3. 更新动态规划数组

    • 对于每个字符 ch,遍历所有可能的前一个字符 i 和当前字符 j,更新 f[j][x]
    • 如果 i 和 j 都不等于 x,则 f[j][x] 增加 f[i][j]
    • 如果 f[j][x] 超过模数 mod,则取模。
  4. 计算结果

    • 最终结果为所有 f[i][j] 的和,取模后输出。

复杂度分析

  • 时间复杂度:O(n×m^2),其中 n 是字符串的长度,m 是字符集的大小(本题中为26)。
  • 空间复杂度:O(m^2),用于存储动态规划数组 f

知识点扩展

  • 动态规划:动态规划是一种通过把原问题分解为相对简单的子问题的方式求解复杂问题的方法。本题中,我们通过动态规划数组 f 记录每个字符作为子序列结尾时,前一个字符的分布情况,从而避免生成回文子串。
  • 字符串处理:字符串处理是计算机科学中的一个重要领域,涉及字符串的匹配、查找、替换等操作。本题中,我们通过遍历字符串,计算每个字符的索引,并更新动态规划数组。
  • 模运算:模运算在处理大数问题时非常有用,可以避免数值溢出。本题中,我们通过模运算确保结果在合理范围内。

代码实现

def solution(s: str) -> int:
    m = 26
    f = [[0 for _ in range(m)] for _ in range(m + 1)]
    mod = 10 ** 9 + 7
    for ch in s:
        x = ord(ch) - ord('a')
        for i in range(m + 1):
            if i != x:
                for j in range(m):
                    if j != x:
                        f[j][x] += f[i][j]
                        if f[j][x] >= mod:
                            f[j][x] -= mod
        f[m][x] += 1
    ans = (sum(f[i][j] for j in range(m) for i in range(m + 1))) % mod
    return ans


if __name__ == '__main__':
    print(solution(s = "aba") == 5)
    print(solution(s = "aaa") == 3)
    print(solution(s = "ghij") == 15)

标签:子串,字符,int,序列,字符串,回文
From: https://blog.csdn.net/2301_78353179/article/details/144716225

相关文章

  • 【Java教程】Day5-01 核心类:String 字符串全面解析
    在Java中,String 是一个非常常用的数据类型,它代表一个字符串。不同于其他类型,String 是一个引用类型,实际在内存中由一个字符数组(char[])来表示。Java的 String 类提供了很多功能强大的方法来操作字符串数据,本篇文章将深入解析 String 类型的相关知识,帮助你更好地理解和......
  • leetcode 05 回文字符串
    leetcode05回文字符串1.描述给你一个字符串,找到里面最长的回文字符串2.事例示例1:输入:s="babad"输出:"bab"解释:"aba"同样是符合题意的答案。示例2:输入:s="cbbd"输出:"bb"3.思路3.1什么是回文字串abbaabcba我们把这种不管是从前到后读还是从后到前读都......
  • 动态规划算法之子序列问题----环绕字符串中唯一的子字符串
    环绕字符串中唯一的字符串https://leetcode.cn/problems/unique-substrings-in-wraparound-string/submissions/589070606/题目描述定义字符串 base 为一个 "abcdefghijklmnopqrstuvwxyz" 无限环绕的字符串,所以 base 看起来是这样的:"...zabcdefghijklmnopqrstuvwxyzab......
  • 【openGauss】Java层传参到openGauss使用拼接字符串拆分为数组方案解决in中用foreach
    【openGauss】Java层传参到openGauss使用拼接字符串拆分为数组方案解决in中用foreach拼接的32767限制一、sql格式二、使用说明三、测试四、SQL解析五、其他说明一、sql格式比如delete:DELETEFROM表名WHERE主键ID字段=any(string_to_array(#{fieldList,jdb......
  • 时间字符串比较大小
    #include<iostream>#include<sstream>#include<iomanip>#include<ctime>boolcompareTimeStrings(conststd::string&timeStr1,conststd::string&timeStr2){std::tmtime1={};std::tmtime2={};std::istri......
  • 301 字符串匹配例题 exkmp
    //301字符串匹配例题.cpp:此文件包含"main"函数。程序执行将在此处开始并结束。///*http://oj.daimayuan.top/course/22/problem/908给你两个字符串a,b,字符串均由小写字母组成,现在问你b在a中出现了几次。输入有多组数据,第一行为数据组数T,每组数据包含两行输入......
  • Flutter OHOS open_filex(以字符串结果打开文件)
    open_filex以字符串结果打开文件的插件用法要使用此插件,请在pubspec.yaml文件中添加open_filex作为依赖项。dependencies:open_filex:^lastVersion例子import'package:open_filex/open_filex.dart';OpenFilex.open("/sdcard/example.txt");鸿蒙OS代码文件是否......
  • 写一个方法判断字符串是否符合USD的格式
    在前端开发中,判断一个字符串是否符合USD(美元)的格式通常涉及检查该字符串是否以美元符号($)开头,并且其余部分是一个有效的数字(可能包含逗号作为千位分隔符,以及小数点用于表示小数部分)。以下是一个使用JavaScript编写的简单方法,用于判断字符串是否符合USD的格式:functionisValidUSDFo......
  • c语言字符串
    字符串定义方式:  charstr[4]={'a','b','c','\0'};   charstr[4]="abc";   //细节一:在底层,实际存储的时候,c语言会将字符串“abc”转换成字符数组进行保存,且末尾加上‘\0’.   //细节二:数组长度要么不写,如果写的话要将结束符‘\0’也计算在内   ......
  • 【字符串】-Lc5-最长回文子串(中心扩展法)
    写在前面  最近想复习一下数据结构与算法相关的内容,找一些题来做一做。如有更好思路,欢迎指正。目录写在前面一、场景描述二、具体步骤1.环境说明2.代码写在后面一、场景描述  最长回文子串。给你一个字符串s,找到s中最长的回文子串。定义:如果字符串的反......