加载中...
1525-字符串的好分割数目(Number of Good Ways to Split a String)
发表于:2021-12-03 | 分类: 中等
字数统计: 1.6k | 阅读时长: 6分钟 | 阅读量:

原文链接: https://leetcode-cn.com/problems/number-of-good-ways-to-split-a-string

英文原文

You are given a string s, a split is called good if you can split s into 2 non-empty strings p and q where its concatenation is equal to s and the number of distinct letters in p and q are the same.

Return the number of good splits you can make in s.

 

Example 1:

Input: s = "aacaba"
Output: 2
Explanation: There are 5 ways to split "aacaba" and 2 of them are good. 
("a", "acaba") Left string and right string contains 1 and 3 different letters respectively.
("aa", "caba") Left string and right string contains 1 and 3 different letters respectively.
("aac", "aba") Left string and right string contains 2 and 2 different letters respectively (good split).
("aaca", "ba") Left string and right string contains 2 and 2 different letters respectively (good split).
("aacab", "a") Left string and right string contains 3 and 1 different letters respectively.

Example 2:

Input: s = "abcd"
Output: 1
Explanation: Split the string as follows ("ab", "cd").

Example 3:

Input: s = "aaaaa"
Output: 4
Explanation: All possible splits are good.

Example 4:

Input: s = "acbadbaada"
Output: 2

 

Constraints:

  • s contains only lowercase English letters.
  • 1 <= s.length <= 10^5

中文题目

给你一个字符串 s ,一个分割被称为 「好分割」 当它满足:将 s 分割成 2 个字符串 p 和 q ,它们连接起来等于 s 且 p 和 q 中不同字符的数目相同。

请你返回 s 中好分割的数目。

 

示例 1:

输入:s = "aacaba"
输出:2
解释:总共有 5 种分割字符串 "aacaba" 的方法,其中 2 种是好分割。
("a", "acaba") 左边字符串和右边字符串分别包含 1 个和 3 个不同的字符。
("aa", "caba") 左边字符串和右边字符串分别包含 1 个和 3 个不同的字符。
("aac", "aba") 左边字符串和右边字符串分别包含 2 个和 2 个不同的字符。这是一个好分割。
("aaca", "ba") 左边字符串和右边字符串分别包含 2 个和 2 个不同的字符。这是一个好分割。
("aacab", "a") 左边字符串和右边字符串分别包含 3 个和 1 个不同的字符。

示例 2:

输入:s = "abcd"
输出:1
解释:好分割为将字符串分割成 ("ab", "cd") 。

示例 3:

输入:s = "aaaaa"
输出:4
解释:所有分割都是好分割。

示例 4:

输入:s = "acbadbaada"
输出:2

 

提示:

  • s 只包含小写英文字母。
  • 1 <= s.length <= 10^5

通过代码

高赞题解

有哪里不明白的可以提出来,我重新说明修改

方法一、暴力解法

实现思路

本题是将字符串划分为左子字符串和右子字符串,并且两串特有的字符个数相同
我们可以直接暴力解法,直接将字符串分割为左右两部分,然后分别统计左右两部分的字符出现情况
然后判断两边特有的字符出现的个数,如果相同,那么好分割数目 + 1

实现代码模型

int len = s.length();
//这里 i = 1 是因为左半部分最少一个字符,结束条件 i < len - 1 是因为右半部分最少一个字符
for(int i = 1; i < len - 1; i++){
    //获取左边的字符情况
    //获取右边的字符情况
    //比较不同的字符情况
}

数据量 1e5,O(n^2) 就是 1e10,暴力肯定超时

方法二、滑动窗口

实现思路

方法一 的暴力解法是每次都 显式地 将字符串分割为左右,即每次都去重新遍历左右子串来获取字符情况
这样时间复杂度是 O(n^2)
但是实际上每次移动的话只是一个字符,相当于左半部分滑窗增大,右半部分滑窗减小
那么我们就可以先统计整个字符串的字符出现情况,先将整个字符串作为右半部分,然后逐一缩减,左半部分逐渐增大
使用两个数组 leftCount 和 rightCount 记录左右两部分的各个字符出现次数
使用两个变量 leftVaild 和 rightVaild 记录左右两部分不同字符的出现次数

比如左半部分字符串为 “aabac”,右半部分字符串为 “acdd”
那么 leftValid = 3,因为有 a b c 三种不同的字符
那么 rightValid = 3,因为有 a c d 三种不同的字符

我们不记录左右两边特有字符,而是记录左右两边的特有和共有字符的原因,如下

我们只需要统计左右两边不同字符的个数即可,如果相同,那么就是好字符串,无需知道是什么字符相同,什么字符不同
比如 aacaba,分割为 “aac” 和 “aba”,左边不同字符个数为 2, 右边不同字符个数为 2
即使两边都存在一个相同的字符 a,那么减去相同的字符 a 后,左边特有字符个数为 1,右边特有字符为 1,那么剩下的仍然是不同的字符个数

实现代码

class Solution {
    public int numSplits(String s) {
      
        int size = 26;
        int[] leftCount = new int[size];
        int[] rightCount = new int[size];
        int leftVaild = 0;
        int rightVaild = 0;
        //先将整个字符串作为右半部分滑窗的内容
        for(char ch : s.toCharArray()){
            int num = ch - 'a';
            if(rightCount[num] == 0){
                rightVaild++;
            }
            rightCount[num]++;
        }

        int c = 0;
        //慢慢调整左半部分滑窗,从左往右遍历,增大左半部分,缩减右半部分,进行滑窗
        for(char ch : s.toCharArray()){
            int num = ch - 'a';
            //左边没有出现过这种字符,那么左边字符 +1
            if(leftCount[num] == 0){
                leftVaild++;
            }
            //右边这是最后一次出现该字符,那么滑窗后右边字符 -1,即这种字符不会再出现在右边了
            if(rightCount[num] == 1){
                rightVaild--;
            }
            leftCount[num]++;
            rightCount[num]--;
            if(leftVaild == rightVaild){
                c++;
            }
        }
        return c;
    }
}

统计信息

通过次数 提交次数 AC比率
5668 8607 65.9%

提交历史

提交时间 提交结果 执行时间 内存消耗 语言
上一篇:
1524-和为奇数的子数组数目(Number of Sub-arrays With Odd Sum)
下一篇:
1526-形成目标数组的子数组最少增加次数(Minimum Number of Increments on Subarrays to Form a Target Array)
本文目录
本文目录