
下面是一段用贪心算法做搜索推荐的 Python 示例。场景用户输入搜索问题系统从候选内容中推荐最相关的若干条。贪心策略是每一步都从剩余候选里选“当前得分最高且满足约束”的内容同时考虑相关度、质量、新鲜度以及推荐结果之间的多样性。pythonimport refrom dataclasses import dataclassfrom typing import List, Setdataclassclass Candidate:id: inttitle: strcontent: strtags: List[str]quality: float 0.8 # 内容质量分freshness: float 0.8 # 新鲜度click_rate: float 0.5 # 历史点击率length: int 100 # 内容长度可用于控制总推荐长度def tokenize(text: str) - Set[str]:简单分词- 英文/数字按单词切分- 中文按连续片段 2-gram 切分不依赖 jieba方便直接运行。text text.lower()tokens set(re.findall(r[a-z0-9], text))chinese_seqs re.findall(r[\u4e00-\u9fa5], text)for seq in chinese_seqs:if len(seq) 1:tokens.add(seq)else:tokens.add(seq)for i in range(len(seq) - 1):tokens.add(seq[i:i 2])return tokensdef jaccard(a: Set[str], b: Set[str]) - float:计算两个集合的 Jaccard 相似度if not a or not b:return 0.0return len(a b) / len(a | b)def base_score(query_tokens: Set[str], cand: Candidate) - float:计算候选内容的基础得分相关性 质量 新鲜度 点击率cand_text cand.title cand.content .join(cand.tags)cand_tokens tokenize(cand_text)relevance jaccard(query_tokens, cand_tokens)# 标签命中额外加权tag_tokens tokenize( .join(cand.tags))tag_relevance jaccard(query_tokens, tag_tokens)relevance max(relevance, tag_relevance)score (0.55 * relevance 0.20 * cand.quality 0.15 * cand.freshness 0.10 * cand.click_rate)return scoredef greedy_recommend(query: str,candidates: List[Candidate],top_k: int 5,max_similarity: float 0.7, # 与已选内容标签相似度超过该值则跳过diversity_penalty: float 0.3, # 相似度带来的得分惩罚max_total_length: int 1000 # 推荐内容总长度限制) - List[Candidate]:贪心推荐每一步从剩余候选中选择当前得分最高、且满足多样性/长度约束的内容。query_tokens tokenize(query)selected: List[Candidate] []selected_tag_sets: List[Set[str]] []total_length 0# 预计算基础得分remaining [(base_score(query_tokens, c), c) for c in candidates]while len(selected) top_k and remaining:best_idx -1best_score -1.0best_cand Nonefor i, (base_s, cand) in enumerate(remaining):cand_tags tokenize( .join(cand.tags))# 计算与已选内容的最大标签相似度max_overlap 0.0for tag_set in selected_tag_sets:max_overlap max(max_overlap, jaccard(tag_set, cand_tags))# 多样性约束太相似就不选if selected and max_overlap max_similarity:continue# 长度约束if total_length cand.length max_total_length:continue# 当前得分 基础得分 - 多样性惩罚current_score base_s - diversity_penalty * max_overlapif current_score best_score:best_score current_scorebest_idx ibest_cand cand# 没有满足约束的候选结束if best_idx -1:break# 选中当前最优selected.append(best_cand)selected_tag_sets.append(tokenize( .join(best_cand.tags)))total_length best_cand.lengthremaining.pop(best_idx)return selectedif __name__ __main__:candidates [Candidate(1, 贪心算法入门, 贪心算法是一种局部最优策略..., [算法, 贪心算法, 基础], 0.90, 0.70, 0.60, 120),Candidate(2, 活动选择问题详解, 用贪心算法解决活动选择..., [贪心算法, 活动选择, 区间调度], 0.85, 0.80, 0.70, 150),Candidate(3, 动态规划与贪心算法区别, 对比动态规划和贪心算法..., [算法, 动态规划, 贪心算法], 0.88, 0.60, 0.65, 180),Candidate(4, 霍夫曼编码实现, 霍夫曼编码的贪心构造..., [贪心算法, 霍夫曼编码, 压缩], 0.80, 0.75, 0.55, 200),Candidate(5, Dijkstra 最短路, Dijkstra 算法是贪心思想..., [贪心算法, 图论, 最短路], 0.90, 0.65, 0.75, 160),Candidate(6, 0/1 背包问题, 0/1 背包不能用贪心..., [动态规划, 背包], 0.95, 0.90, 0.80, 140),Candidate(7, 分数背包贪心解法, 分数背包可以按单位价值贪心..., [贪心算法, 背包, 分数背包], 0.82, 0.70, 0.60, 130),Candidate(8, 贪心算法常见错误, 贪心算法不是万能的..., [贪心算法, 算法, 反例], 0.87, 0.80, 0.72, 110),]query 贪心算法 活动选择recs greedy_recommend(query, candidates, top_k4, max_total_length600)print(f查询{query}\n推荐结果)for i, c in enumerate(recs, 1):print(f{i}. {c.title} | 标签{, .join(c.tags)} | 质量{c.quality} | 长度{c.length})这段代码的核心贪心逻辑在 greedy_recommend 里1. 先计算每个候选内容的基础得分2. 每一步遍历剩余候选3. 计算它和已选内容的标签相似度并做多样性惩罚4. 选择当前得分最高、且满足相似度阈值和长度限制的内容5. 加入推荐列表重复直到选够 top_k 或没有可用候选。你可以根据实际业务调整这些参数· top_k推荐几条· max_similarity控制内容多样性· diversity_penalty相似内容的降权幅度· max_total_length控制推荐总长度· base_score 里的权重相关性、质量、新鲜度、点击率各占多少。文章仅供参考用。