Dynamic Programming学习笔记 (36) - 字符串的好分割数目 (力扣# 1525)

130 阅读2分钟

本题出自力扣题库第1525题。题面大意如下:

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

示例:

输入: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 个不同的字符。

题解:

以长度为5的字符串为例,我们可以得到p和q中不同字符数目的比较关系

 p          q
 s[0:0], s[1:4]    
 s[0:1], s[2:4]    
 s[0:2], s[3:4]    
 s[0:3], s[4:4]   

由此,我们使用两个循环来分别计算左右两边的列表,第一个循环按数组下标顺序从小到大,第二个则从大到小,然后依次比较两个对应的数字是否相等即可。

Java代码如下:

import java.util.HashSet;
import java.util.Set;

class Solution {
    public int numSplits(String s) {
        char[] chars = s.toCharArray();
        int N = chars.length;

        if (N <= 1) {
            return 0;
        }

        int[] dpLeft = new int[N - 1];
        int[] dpRight = new int[N - 1];

        Set<Character> leftSet = new HashSet<>();
        int count = 0;
        for (int i = 0; i < N - 1; i++) {
            if (leftSet.add(chars[i])) {
                count++;
            }
            dpLeft[i] = count;
        }

        Set<Character> rightSet = new HashSet<>();
        count = 0;
        for (int j = N - 1; j >= 1; j--) {
            if (rightSet.add(chars[j])) {
                count++;
            }
            dpRight[j - 1] = count;
        }

        count = 0;
        for (int i = 0; i < N - 1; i++) {
            if (dpLeft[i] == dpRight[i]) {
                count++;
            }
        }

        return count;
    }
}