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
1. 问题描述:给你一个字符串 s ,请你拆分该字符串,并返回拆分后唯一子字符串的最大数目。字符串 s 拆分后可以得到若干 非空子字符串 ,这些子字符串连接后应当能够还原为原字符串。但是拆分出来的每个子字符串都必须是唯一的 。注意:子字符串 是字符串中的一个连续字符序列。示例 1:输入:s = "ababccc"输出:5解释:一种最大拆分方法为 ['a', 'b', 'ab', 'c', 'cc'] 。像 ['a', 'b', 'a', 'b', 'c', 'cc'] 这样拆分不满足题目
给定由 [a-z] 26 个英文小写字母组成的
字符串
A 和 B,其中 A 中可能存在重复字母,B 中不会存在重复字母
现从
字符串
A 中按规则挑选一些字母,可以组成
字符串
B。
挑选规则如下:
1) 同一个位置的字母只能被挑选一次
2) 被挑选字母的相对先后顺序不能改变
求最多可以同时从 A 中挑选多少组能组成 B 的
字符串
什么是
子
序列
子
序列和
子
串不一样,字串的求法很简单,用两层for循环即可得到。比如absv这个
字符串
,他的字串全部就是a,ab,abs,absv,b,bs,bsv,s,sv,v,和空,但是它的
子
序列选择的方式更多,中间可以有空隔,比如asv也是其
子
序列,所以求
子
序列,我们可以用
递归
,类似二叉树的求法,每一个位置都有两个状态,选与不选
// str 固定参数
// 来到了str[index]字符,index是位置
// str[0..index-1]已经走过了!之前的决定,都在path上
// 之前的决
集合中的所有元素对于每一个
子
集来说,都有两种可能性:在
子
集中或是不在
子
集中。
各个元素的这两种可能性组合起来,组成了一个集合的所有
子
集。这也是每一个集合都有2^n个
子
集的原因所在。
比如 char *str = "abcd";对于str这个单词集合,其一个
子
集 空集,就是所有元素都不在该
子
集中,再如”abc”,这个
子
集,是元素a,b,c在
子
集中,元素d不在
子
集中。
我们把元素这种在或不在
子
集
方法一:回溯
拆分
给定的
字符串
,要求
拆分
后的每个
子
字符串
唯一
,求
子
字符串
的
最大
数目
,可以通过回溯
算法
实现。
对于长度为 n的
字符串
,有n−1个
拆分
点。从左到右遍历
字符串
,对于每个
拆分
点,如果在此
拆分
之后,新得到的一个非空
子
字符串
(即
拆分
点左侧的最后一个被
拆分
出的非空
子
字符串
)与之前
拆分
出的非空
子
字符串
都不相同,则当前的
拆分
点可以进行
拆分
,然后继续对剩下的部分(即
拆分
点右侧的部分)进行
拆分
。
判断
拆分
出的非空
子
字符串
是否有重复时,可以使用哈希表。
当整个
字符串
拆分
完毕时,计算
拆分
得到的非空
子
字符串
的.
递归
删除
字符串
里某字符是一种常用的
字符串
删除技巧,其主要思想是通过
递归
函数实现对
字符串
字符的删除,直至
字符串
中不存在要删除的字符为止。
首先,定义
递归
函数,函数接收原
字符串
和要删除的字符作为参数。在函数内部,判断
字符串
是否为空或者长度为0,如果是,则返回空
字符串
。否则,取出第一个字符进行判断,如果是要删除的字符,则
递归
调用函数,并将删除字符后的
字符串
作为参数传入,最终返回
递归
函数的结果;否则,将第一个字符加入到结果
字符串
中,
递归
调用函数并将剩余
字符串
作为参数传入,最终返回结果
字符串
。这样不断
递归
调用,直至返回的
字符串
中不存在要删除的字符。
需要注意的是,
递归
删除
字符串
中某字符虽然简单,但需要考虑到边界情况和
算法
复杂度问题。在
递归
调用时,需要注意每次截取
字符串
的开销,因此尽量减少
字符串
操作次数,以提高
算法
效率。
总之,可以通过
递归
删除
字符串
里某字符的方法来方便地处理
字符串
,提高程序效率。
怀念小时候725:
1114 放苹果(递归)
yuzhang_zy: