1. 问题描述:
给你一个字符串 s ,请你拆分该字符串,并返回拆分后唯一子字符串的最大数目。
字符串 s 拆分后可以得到若干非空子字符串 ,这些子字符串连接后应当能够还原为原字符串。但是拆分出来的每个子字符串都必须是唯一的 。
注意:子字符串 是字符串中的一个连续字符序列。
示例 1:
输入:s = "ababccc"
输出:5
解释:一种最大拆分方法为 ['a', 'b', 'ab', 'c', 'cc'] 。像 ['a', 'b', 'a', 'b', 'c', 'cc'] 这样拆分不满足题目要求,因为其中的 'a' 和 'b' 都出现了不止一次。
示例 2:
输入:s = "aba"
输出:2
解释:一种最大拆分方法为 ['a', 'ba'] 。
示例 3:
输入:s = "aa"
输出:1
解释:无法进一步拆分字符串。
提示:
1 <= s.length <= 16
s 仅包含小写英文字母
来源:https://leetcode-cn.com/problems/split-a-string-into-the-max-number-of-unique-substrings/
2. 思路分析:
① 从题目中可以知道我们需要将字符串分解为若干个唯一的子字符串并且使得到的子字符串的数目是最大的,所以比较容易想到的是使用递归去尝试所有可能的字符串的拆分情况,比如从当前的索引开始,尝试截取1,2,3...k个字符(因为截取的字符串可能与之前的重复的所以必须要尝试不同的截取长度使得当前截取的字符串与之前的不同),并且从字符串的每一个位置开始截取的时候都可以这样尝试所以我们可以使用for循环进行递归,尝试从当前索引开始截取k个长度的字符串:
在for循环中递归截取字符串的时候需要考虑边界问题,因为字符串的长度最大为len(s),而当前的索引为index,所以截取的最大长度就为len(s) - index。
② 我们递归的时候需要使用set集合来记录中间截取的字符串,判断当前截取的字符串是否以之前截取的字符串发生重复,并且在递归方法调用之前需要将截取的字符串加入到set集合中,当递归方法结束之后需要将加入的最后一个字符串删除掉(回溯),这样才可以尝试for循环中的下一个可能截取的字符串。
③ 凡是事先不知道怎么样的划分或者组合才可以得到最佳的解决方案都是可以递归的方法尝试所有的可能的方法得到最佳结果的。
3. 代码如下:
import sys
class Solution:
res = -sys.maxsize
"""
@param index: 字符串截取的开始位置
@param rec: 记录中间结果看判断是否存在重复的元素
@return:
"""
def recursion(self, s: str, index: int, rec: set):
# if的第一个判断条件是剪枝当发现递归的最终结果小于等于了之前的res那么直接return了
if len(rec) + len(s) - index + 1 <= self.res or index == len(s):
self.res = max(self.res, len(rec))
return
# 使用for循环尝试从当前索引index位置开始截取k个长度,需要注意边界为len(s) - index + 1
for i in range(1, len(s) - index + 1):
# s[index: index + i]为python中的切片操作
if s[index: index + i] not in rec:
rec.add(s[index: index + i])
self.recursion(s, index + i, rec)
# 回溯, 以便可以尝试其他字符串截取情况
rec.remove(s[index: index + i])
def maxUniqueSplit(self, s: str) -> int:
self.recursion(s, 0, set())
return self.res