当前位置: 首页 > news >正文

贪心算法实验1

贪心算法实验:从理论到实践的完整指南

前言

贪心算法是计算机科学中一种重要的算法思想,它通过一系列局部最优选择来达到全局最优解。在本次实验中,我们将通过四个经典的编程问题,深入理解贪心算法的基本思路和实际应用。本文将详细介绍每个问题的分析过程、贪心策略设计以及完整的代码实现。

实验目标

本次实验的主要目标包括:

  1. 理解贪心算法的基本思路,实现增减字符串匹配、最大数问题等经典例题
  2. 掌握编写代码和调试程序的技巧
  3. 学会分析算法的时间复杂度
  4. 培养程序设计思路
  5. 提升撰写技术文档的能力

实验环境

硬件环境:PC微机

软件环境

  • Windows操作系统
  • Python 3.7
  • PyCharm
  • Aistudio
  • Jupyter Notebook
  • Eclipse

贪心算法原理

贪心算法(Greedy Algorithm)的核心思想是:在每一步选择中都采取在当前状态下最好或最优的选择,即局部最优选择,从而希望导致结果是全局最优的。贪心算法并不一定总能得到全局最优解,但在许多情况下,特别是具有最优子结构的问题中,它能够有效地找到最优解。

贪心算法的适用条件:

  1. 贪心选择性质:每一步的局部最优选择能够导致全局最优解
  2. 最优子结构:问题的最优解包含其子问题的最优解

实验内容

一、增减字符串匹配

问题分析

给定一个由’I’和’D’组成的字符串s,需要构建一个长度为n+1的排列perm(其中n为s的长度),排列中的元素为[0,n]内的所有整数。排列需满足:

  • 若s[i]为’I’,则perm[i] < perm[i+1]
  • 若s[i]为’D’,则perm[i] > perm[i+1]

核心是找到一种符合相邻元素大小关系的排列方式,且需包含0到n的所有整数。

贪心策略设计

采用双指针贪心思路,维护两个指针low和high,分别初始化为0和n。

  • 当遇到字符’I’时,选择当前最小的可用数字(即low)加入排列,因为需要下一个元素更大,保留较大数字供后续使用
  • 当遇到字符’D’时,选择当前最大的可用数字(即high)加入排列,因为需要下一个元素更小,保留较小数字供后续使用
  • 遍历结束后,将剩余的最后一个数字(此时low与high相等)加入排列
编码实现
def strsum(s):n = len(s)low, high = 0, nperm = []for char in s:if char == 'I':perm.append(low)low += 1else:perm.append(high)high -= 1perm.append(low)return permtest = "IDID"
print(strsum(test))  # 输出示例:[0, 4, 1, 3, 2]

二、最大数问题

问题分析

给定一组非负整数,需要重新排列每个数的顺序(每个数不可拆分),使它们组成一个最大的整数。由于输出结果可能非常大,需返回字符串形式。

核心是确定两个数字的排列顺序,以保证拼接后的结果最大。例如对于3和30,330大于303,因此3应排在30之前。

贪心策略设计

贪心策略体现在排序规则上:对于任意两个数字x和y,将它们转换为字符串后,比较拼接结果xy和yx的大小。

  • 若xy的字典序大于yx,则x应排在y之前
  • 否则y排在x之前

通过这种自定义排序规则,将数组中的数字排序后拼接,即可得到最大整数。同时需处理特殊情况,如排序后结果以0开头(如[0,0]),需返回"0"而非"00"。

编码实现
from functools import cmp_to_keydef largestNumber(nums):# 转换为字符串列表str_nums = list(map(str, nums))# 自定义比较函数:若xy > yx,则x应在y前def compare(x, y):if x + y > y + x:return -1  # x排在y前else:return 1   # y排在x前# 按自定义规则排序str_nums.sort(key=cmp_to_key(compare))# 处理全零情况if str_nums[0] == '0':return '0'# 拼接结果return ''.join(str_nums)print(largestNumber([3,30,34,5,9]))  # 输出:"9534330"

三、买卖股票的最佳时机 II

问题分析

给定一支股票的价格序列,每天可以决定购买或出售股票,且任何时候最多持有一股股票(可当天买入后卖出)。目标是计算能获得的最大利润。

核心是捕捉所有的上涨区间,因为多次买卖可以累积利润。例如在价格从1涨到5时,1买入5卖出可获利4,与1买入3卖出再3买入5卖出的总利润相同。

贪心策略设计

贪心思路是只要当天的股票价格高于前一天的价格,就将两者的差价计入总利润。因为可以在当天卖出前一天买入的股票,再立即买入当天的股票(若后续仍上涨),这样每一段上涨的差价都能被捕捉到。

通过累积所有正的相邻差价,即可得到最大利润。

编码实现
def maxProfit(prices):max_profit = 0for i in range(1, len(prices)):# 若当天价格高于前一天,累加差价if prices[i] > prices[i-1]:max_profit += prices[i] - prices[i-1]return max_profit# 测试示例
test_cases = [[7, 1, 5, 3, 6, 4],  # 预期输出:7[1, 2, 3, 4, 5],    # 预期输出:4[7, 6, 4, 3, 1]     # 预期输出:0
]for prices in test_cases:print(f"输入:{prices},输出:{maxProfit(prices)}")

四、分发糖果问题

问题分析

一群孩子站成一排,每个孩子有评分,需分发糖果并满足:

  • 每个孩子至少1个糖果
  • 若一个孩子的评分高于相邻孩子,则他的糖果数必须多于该相邻孩子

目标是找到最少需要的糖果总数。核心是同时满足左右两侧的约束,避免因单侧判断导致的遗漏。

贪心策略设计

采用两次遍历的贪心策略:

  1. 第一次从左到右遍历,若右边孩子的评分高于左边,则右边孩子的糖果数更新为左边孩子的糖果数加1(保证左邻约束)
  2. 第二次从右到左遍历,若左边孩子的评分高于右边,且左边孩子当前的糖果数不大于右边,则左边孩子的糖果数更新为右边孩子的糖果数加1(保证右邻约束)

两次遍历后,所有约束均被满足,且总糖果数最少。

编码实现
def candy(ratings):n = len(ratings)if n == 0:return 0# 初始化每个孩子至少1个糖果candies = [1] * n# 从左到右:处理右边评分高于左边的情况for i in range(1, n):if ratings[i] > ratings[i-1]:candies[i] = candies[i-1] + 1# 从右到左:处理左边评分高于右边的情况for i in range(n-2, -1, -1):if ratings[i] > ratings[i+1]:candies[i] = max(candies[i], candies[i+1] + 1)return sum(candies)# 测试示例
test_cases = [[1, 0, 2],  # 预期输出: 5[1, 2, 2],  # 预期输出: 4[1, 3, 2, 2, 1]  # 预期输出: 7
]for i, ratings in enumerate(test_cases):result = candy(ratings)print(f"测试用例 {i+1}: {ratings},最少需要糖果数: {result}")

结果分析

四个编程题的求解结果均符合问题要求,其核心原因在于所采用的算法策略能够精准匹配问题的约束与目标。

对于增减字符串匹配问题,通过双指针贪心策略重构排列时,low和high的动态调整确保了每一步都能满足"I"或"D"的相邻关系要求,最终加入剩余数值后,排列既包含[0,n]的所有整数,又完全符合字符串s的大小关系描述。

最大数问题中,通过自定义排序规则(比较两个数字拼接后的字符串大小)实现最大整数的构建,结果的正确性源于该规则能确保每对数字的排列都是局部最优的——即对于任意两个数字x和y,x在y前总能使拼接结果更大。

股票最大利润求解中,贪心策略通过累积所有上涨区间的差价,本质上与动态规划思路一致——因为多次买卖的总利润等价于捕捉所有正向波动,有效利用了"可当天买卖"的规则。

分发糖果问题中,两次遍历的贪心策略有效平衡了左右两侧的约束条件。第一次左到右遍历确保右侧评分更高的孩子获得更多糖果,第二次右到左遍历通过max函数修正左侧评分更高的孩子的糖果数,既避免了重复增加,又保证了所有相邻约束均被满足。

实验总结

本次实验通过求解四个典型编程问题,系统实践了贪心算法的核心思想,深化了对"问题分析—策略设计—代码实现—结果验证"完整解题流程的理解。

实验的核心收获在于明确了算法策略与问题特性的匹配原则:当问题可通过局部最优选择累积达成全局最优时,贪心算法是高效且简洁的解决方案。每个问题的策略设计都与问题的核心约束高度匹配,确保了结果的正确性与最优性。

在解题过程中,问题核心约束的精准把握是关键前提。例如分发糖果问题需同时满足"相邻高分多糖果"和"最少糖果数"的双重要求,因此设计了两次遍历的贪心策略;组成最大整数问题的核心在于数字拼接规则,因此自定义排序规则成为突破点。

此外,边界情况的处理能力也得到了强化,如全零数组的结果优化、空输入的判断,这些细节虽不影响核心算法逻辑,却直接决定了代码的健壮性和结果的正确性,是编程实践中不可或缺的环节。

本次实验不仅巩固了贪心算法的应用场景和实现技巧,更培养了结构化的解题思维:面对复杂问题时,先拆解核心约束与目标,再选择适配的算法策略,最后通过边界处理和结果验证完善代码。这些能力将有效支撑后续更复杂的算法问题求解。

http://www.dtcms.com/a/607068.html

相关文章:

  • 怎样做一个网站电子商务平台的类型
  • 好的网站建设公司哪家好北京优化推广公司
  • 易语言模块反编译与破解技术解析 | 深入理解反编译的原理与应用
  • 网站开发是哪个营销方案策划书
  • 用ps做一份网站小程序在线制作模板
  • Vite 7 + React 19 升级清单
  • 微网站怎么建设wordpress餐饮
  • 中国建设银行社保卡网站wordpress看板猫
  • 动易网站中添加邮箱seo推广主要做什么
  • 网站建设教程吧百度收录入口提交
  • 密度估计与人群计数的深度学习方法综述
  • 坪地网站建设游戏网页设计
  • Spring Data JAP中Pageable对象如何从1开始分页,而不是从0开始
  • 勇闯前后端:Java 基础语法 + ATM 同步实现
  • 城市建设网站鹤岗市云集网站哪个公司做的
  • 为什么用wp做网站健身会所网站模板
  • 不同架构下readdir() 返回值中 struct dirent.d_type 的取值差异与解决方法
  • 衡水做网站建设公司网站建设发展趋势
  • 2025 济南专业化科技孵化器申报攻略:中承信安专业测试服务助力企业通关
  • 浙江省建设协会网站首页济南网络推广seo
  • linux系统学习(11、shell编程)
  • SAP FICO应付暂估款账龄分析表
  • 牡丹园网站建设p2p网站开发维护
  • 做网站系统学校淮滨网站建设
  • wordpress模版做网站宁波网络营销服务
  • C语言编译器哪个好学 | 学习C语言编译器的入门指南与推荐
  • 【036】阳乐音乐厅购票平台
  • Katalon Studio 最佳实践:提升自动化测试效率的实用指南
  • Vue项目实战《尚医通》,登录模块表单自定义校验规则,笔记29
  • 数据分析笔记05:区间估计