在计算机科学中,贪心算法是一种在每一步选择中都采取当前状态下最好或最优的选择,从而希望导致结果是全局最好或最优的算法策略。贪心算法通常用于解决最优解问题,它通过局部最优解来构建全局最优解。本文将详细介绍50个经典贪心算法习题,并分析其实战应用。
1. 0-1背包问题
问题描述:给定n件物品和一个容量为V的背包,每件物品的重量和价值分别为w[i]和v[i],求如何选择物品使得背包内物品的总价值最大。
贪心策略:选择价值与重量比最大的物品放入背包,直到背包容量满。
代码示例:
def knapsack(weights, values, capacity):
n = len(weights)
items = sorted(zip(values, weights), key=lambda x: x[0]/x[1], reverse=True)
total_value = 0
for value, weight in items:
if capacity >= weight:
total_value += value
capacity -= weight
else:
break
return total_value
2. 最长不上升子序列
问题描述:给定一个无序数组,找出最长的不上升子序列的长度。
贪心策略:维护一个数组,记录以每个数字结尾的最长不上升子序列的长度。
代码示例:
def longest_non_increasing_subsequence(nums):
n = len(nums)
dp = [1] * n
for i in range(1, n):
for j in range(i):
if nums[i] <= nums[j]:
dp[i] = max(dp[i], dp[j] + 1)
return max(dp)
3. 股票买卖最佳时机
问题描述:给定一个数组,其中包含某支股票在连续每一天的价格,找出能够通过一次买卖股票获得最大利润的时间点。
贪心策略:在遍历数组的过程中,记录当前最小价格和最大利润。
代码示例:
def max_profit(prices):
min_price = float('inf')
max_profit = 0
for price in prices:
min_price = min(min_price, price)
max_profit = max(max_profit, price - min_price)
return max_profit
4. 零钱兑换
问题描述:给定一个数组,其中包含各种面额的硬币,和一个目标金额,求出兑换该金额所需的最少硬币个数。
贪心策略:从最大面额的硬币开始,每次尽可能多地使用硬币。
代码示例:
def coin_change(coins, amount):
dp = [float('inf')] * (amount + 1)
dp[0] = 0
for coin in coins:
for i in range(coin, amount + 1):
dp[i] = min(dp[i], dp[i - coin] + 1)
return dp[amount] if dp[amount] != float('inf') else -1
5. 最短路径问题
问题描述:给定一个带权重的有向图,求图中任意两个顶点之间的最短路径。
贪心策略:使用Dijkstra算法,每次选择当前最短路径的顶点,更新其相邻顶点的最短路径。
代码示例:
import heapq
def dijkstra(graph, start):
distances = {vertex: float('inf') for vertex in graph}
distances[start] = 0
priority_queue = [(0, start)]
while priority_queue:
current_distance, current_vertex = heapq.heappop(priority_queue)
if current_distance > distances[current_vertex]:
continue
for neighbor, weight in graph[current_vertex].items():
distance = current_distance + weight
if distance < distances[neighbor]:
distances[neighbor] = distance
heapq.heappush(priority_queue, (distance, neighbor))
return distances
6. 最长公共子序列
问题描述:给定两个字符串,找出它们的最长公共子序列。
贪心策略:使用动态规划,构建一个二维数组,记录两个字符串的公共子序列的长度。
代码示例:
def longest_common_subsequence(str1, str2):
m, n = len(str1), len(str2)
dp = [[0] * (n + 1) for _ in range(m + 1)]
for i in range(1, m + 1):
for j in range(1, n + 1):
if str1[i - 1] == str2[j - 1]:
dp[i][j] = dp[i - 1][j - 1] + 1
else:
dp[i][j] = max(dp[i - 1][j], dp[i][j - 1])
return dp[m][n]
7. 旅行商问题
问题描述:给定一个带权重的有向图,求出一条遍历所有顶点恰好一次的最短路径。
贪心策略:使用遗传算法,模拟自然选择和遗传过程,逐步优化路径。
代码示例:
import random
def genetic_algorithm(graph, population_size, mutation_rate, generations):
# 初始化种群
population = [random.sample(graph.keys(), len(graph)) for _ in range(population_size)]
for generation in range(generations):
# 计算适应度
fitness = lambda path: sum(graph[path[i]][path[i + 1]] for i in range(len(path) - 1))
# 选择、交叉和变异
new_population = []
for _ in range(population_size):
parent1, parent2 = random.sample(population, 2)
child = parent1[:len(parent1) // 2] + parent2[len(parent1) // 2:]
if random.random() < mutation_rate:
child = random.sample(child, len(child))
new_population.append(child)
population = new_population
# 返回最优路径
best_path = min(population, key=fitness)
return best_path
总结
本文介绍了50个经典贪心算法习题及其实战应用。通过这些习题,读者可以深入了解贪心算法的原理和应用场景。在实际开发中,合理运用贪心算法可以提高算法效率,解决实际问题。
