一、动态规划
1、我的思路
dp记录以i为结尾的所有子串中的唯一字符的总数,答案res就是将dp数组求和,但超时了。
提交一:
class Solution:
def uniqueLetterString(self, s: str) -> int:
nlen = len(s)
dp = [0] * nlen # 记录以i为结尾的所有子串中的唯一字符的总数
assist = [[0] * 26 for _ in range(nlen)] # 记录 i 到当前遍历位置为止的子串中,有哪些字符
res = 0
for i in range(nlen):
tmp = 0
assist[i][ord(s[i]) - 65] += 1
# 初始状态
if i == 0:
dp[i] = 1
else:
for j in range(i): # 遍历以i结尾的所有子串
if assist[j][ord(s[i]) - 65] == 0: # 新字符不会给该子串带来重复字符
tmp += 1 # 该子串在前一个dp的结果上,贡献1个唯一字符
elif assist[j][ord(s[i]) - 65] == 1: # 带来重复
tmp -= 1 # 该子串在前一个dp的结果上,去掉1个唯一字符
# else: # 带来重复,但已经在前一个dp的结果中去掉过了
# pass # 则不需要变动
assist[j][ord(s[i]) - 65] += 1 # 辅助数组更新
print("tmp:", tmp)
# 似乎不需要记录有多少个某字符
dp[i] = dp[i-1] + tmp + 1 # 加上这个一个字符的子串
res += dp[i]
print("assist函数:", assist)
print("dp函数:", dp)
return res
把数组改成用两个变量,还是超时了。
提交二:
class Solution:
def uniqueLetterString(self, s: str) -> int:
nlen = len(s)
# dp = [0] * nlen # 记录以i为结尾的所有子串中的唯一字符
pre = 0
cur = 0
assist = [[0] * 26 for _ in range(nlen)] # 记录 i 到当前遍历位置为止的子串中,有哪些字符
# 初始状态
# dp[0] = 1
# assist[0]
res = 0
for i in range(nlen):
tmp = 0
assist[i][ord(s[i]) - 65] += 1
if i == 0:
# dp[i] = 1
# pre = 0
cur = 1
pre = cur
else:
for j in range(i): # 遍历以i结尾的所有子串
if assist[j][ord(s[i]) - 65] == 0: # 新字符不会给该子串带来重复字符
tmp += 1 # 该子串在前一个dp的结果上,贡献1个唯一字符
elif assist[j][ord(s[i]) - 65] == 1: # 带来重复
tmp -= 1 # 该子串在前一个dp的结果上,去掉1个唯一字符
else: # 带来重复,但已经在前一个dp的结果中去掉过了
pass # 则不需要变动
assist[j][ord(s[i]) - 65] += 1 # 辅助数组更新
print("tmp:", tmp)
# 似乎不需要记录有多少个某字符
# dp[i] = dp[i-1] + tmp + 1 # 加上这个一个字符的子串
cur = pre + tmp + 1
pre = cur
# res += dp[i]
res += cur
print("assist函数:", assist)
# print("dp函数:", dp)
return res
2、答案思路
我的理解:
这个方法是遍历每个下标的字符char,统计出【只包含一个该字符char的所有子串】,这个数量就是该字符char能贡献给最终答案的【所有子串的独特字符数量】。 将题目【s的所有子串中唯一字符的数量有多少】转换为【s中的每个字符是唯一字符的子串有多少】
class Solution:
def uniqueLetterString(self, s: str) -> int:
LETTER = collections.defaultdict(list)
for i, char in enumerate(s):
LETTER[char].append(i) # 记录每个字母的出现位置的所有下标
res = 0
for letter in LETTER.values(): # 遍历每个出现的字母,获得其所有下标
letter = [-1] + letter + [len(s)] # 补足前后两断点,方便统一计算
for index in range(1, len(letter)-1): # 遍历每个下标,除前后两端
res += (letter[index] - letter[index-1]) * (letter[index+1] - letter[index])
return res