目标
给定已知字符串和相关的词表集合,实现该字符串的所有切分方式。
待切分字符串
#待切分文本
sentence = "经常有意见分歧"
对应的词表
#词典;每个词后方存储的是其词频,词频仅为示例,不会用到,也可自行修改
Dict = {"经常":0.1,
"经":0.05,
"有":0.1,
"常":0.001,
"有意见":0.1,
"歧":0.001,
"意见":0.2,
"分歧":0.2,
"见":0.05,
"意":0.05,
"见分歧":0.05,
"分":0.1}
要求切分结果
#目标输出;顺序不重要
target = [
['经常', '有意见', '分歧'],
['经常', '有意见', '分', '歧'],
['经常', '有', '意见', '分歧'],
['经常', '有', '意见', '分', '歧'],
['经常', '有', '意', '见分歧'],
['经常', '有', '意', '见', '分歧'],
['经常', '有', '意', '见', '分', '歧'],
['经', '常', '有意见', '分歧'],
['经', '常', '有意见', '分', '歧'],
['经', '常', '有', '意见', '分歧'],
['经', '常', '有', '意见', '分', '歧'],
['经', '常', '有', '意', '见分歧'],
['经', '常', '有', '意', '见', '分歧'],
['经', '常', '有', '意', '见', '分', '歧']
]
思路
实现的过程主要是按照动态规划思想做的。主要思路如下:
"""
# 动态规划(DP)是解决字符串全切分问题的有效方法,其核心思想是将问题分解为子问题,并存储子问题的解以避免重复计算。以下是详细思路与实现步骤:
# 1. 问题定义
# 输入:
# 一个字符串 sentence 和一个词典 Dict(包含所有可能的词)。
# 目标:
# 输出所有可能的切分方式,使得每个切分结果中的词都存在于词典中。
# 2. 动态规划思路
# (1) 子问题定义
# 定义 dp[i] 为从位置 i 到字符串末尾的所有可能切分方式。
# 最终目标:求 dp,即从字符串开头到末尾的所有切分方式。
# (2) 状态转移方程
# 从位置 i 开始,尝试所有可能的词 word = sentence[i:j],其中 j 的范围为 [i+1, min(i+max_len, n)](max_len 为词典中最长词的长度)。
# 若 word 存在于词典中,则将 word 与 dp[j] 的所有切分方式合并,作为 dp[i] 的一部分。
# 状态转移方程:
# dp[i] = ⋃ { [word] + seg | seg ∈ dp[j] }
# 其中 j = i + len(word)。
# (3) 初始化
# dp[n] = [[]]:表示从字符串末尾到末尾的切分方式为空列表(即空字符串的切分方式)。
# (4) 计算顺序
# 从右向左计算 dp[i],因为 dp[i] 依赖于 dp[j](j > i)。
# 3. 实现步骤
# (1) 预处理
# 提取词典中的词,并计算最长词长度 max_len。
# 将词典存储为集合(set),以提高查询效率。
# (2) 动态规划表构建
# 初始化 dp 表,大小为 n+1,其中 n 为字符串长度。
# 从右向左遍历字符串,填充 dp[i]。
# (3) 结果提取
# dp 即为所有可能的切分方式。
"""
实现
def all_cut(sentence, Dict):
# 提取词典中的词并计算最大词长
vocab = set(Dict.keys())
max_len = max(len(word) for word in vocab) if vocab else 0 # max_len = 3
n = len(sentence) # n=7
# 初始化动态规划表:dp[i] 表示从位置i到句尾的所有切分方式
dp = [[] for _ in range(n + 1)] #8个空列表
dp[-1] = [[]] # 空字符串的切分方式为空列表
# 从右向左填充dp表
for i in range(n - 1, -1, -1): # i=6,5,4,3,2,1,0
max_j = min(i + max_len, n) # 避免越界 max_j=min((9,8,7,6,5,4,3),7)=(7,7,7,6,5,4,3)
for j in range(i + 1, max_j + 1): #word从末尾往前开始取词
word = sentence[i:j]
if word in vocab:
# 合并当前词与后续切分结果
for rest in dp[j]:
dp[i].append([word] + rest)
return dp[0]
测试结果
if __name__=="__main__":
res = all_cut(sentence,Dict)
for seg in res:
print(seg)
运行结果:

2954

被折叠的 条评论
为什么被折叠?



