目录
1.贪心法
贪心法(Greedy Algorithm): 贪心法是一种基于局部最优选择的算法思想,每次都选择当前看起来最优的解决方案。尽管贪心法不保证总是能得到全局最优解,但在某些问题上可以达到较好的近似解。
- 在某些问题中,贪心法提供了一种简单而高效的求解方法。
- 贪心法常用于解决优化问题,其中目标是找到满足一定约束条件下的最优解或近似最优解。
# 跳跃游戏问题:给定一个非负整数列表,每个元素表示当前位置的最大跳跃长度,判断是否能从起点跳到终点。
def can_jump(nums):
max_reach = 0
for i in range(len(nums)):
if i > max_reach:
return False
max_reach = max(max_reach, i + nums[i])
return True
# 测试
nums = [2, 3, 1, 1, 4]
print(can_jump(nums))
2.分治法
分治法(Divide and Conquer): 分治法将一个问题划分为若干个子问题,并通过递归求解各个子问题,最后将这些子问题的解合并得到原问题的解。
- 分治法常用于解决复杂问题,将其划分为更小、更具体的子问题。
- 分治法能够提高问题的求解效率,并降低算法的时间复杂度。
# 归并排序:使用分治法对一个列表进行排序
def merge_sort(arr):
if len(arr) <= 1:
return arr
mid = len(arr) // 2
left = merge_sort(arr[:mid])
right = merge_sort(arr[mid:])
return merge(left, right)
def merge(left, right):
merged = []
i = j = 0
while i < len(left) and j < len(right):
if left[i] <= right[j]:
merged.append(left[i])
i += 1
else:
merged.append(right[j])
j += 1
merged.extend(left[i:])
merged.extend(right[j:])
return merged
# 测试
arr = [7, 2, 5, 1, 8, 3]
sorted_arr = merge_sort(arr)
print(sorted_arr)
3.回溯法
回溯法(Backtracking): 回溯法是一种试探性的搜索算法,通过逐步构建解决方案并在不满足条件时进行回溯,重新尝试其他可能的选择。
- 回溯法常用于解决组合、排列、搜索等问题,其中需要尝试多个可能的选择
# N皇后问题:在N×N的棋盘上放置N个皇后,使得它们不能互相攻击。
def solve_n_queens(n):
result = []
board = [['.'] * n for _ in range(n)]
def backtrack(row):
if row == n:
result.append([''.join(row) for row in board])
return
for col in range(n):
if is_valid(row, col):
board[row][col] = 'Q'
backtrack(row + 1)
board[row][col] = '.'
def is_valid(row, col):
for i in range(row):
if board[i][col] == 'Q':
return False
if col-row+i >= 0 and board[i][col-row+i] == 'Q':
return False
if col+row-i < n and board[i][col+row-i] == 'Q':
return False
return True
backtrack(0)
return result
# 测试
n = 4
queens = solve_n_queens(n)
for queen in queens:
for row in queen:
print(row)
print()
4.分支限界法
分支限界法(Branch and Bound): 分支限界法是一种通过剪枝策略进行搜索的优化算法。它通过扩展当前节点的所有可能子节点,并根据问题的约束条件和目标函数来评估和排序这些子节点,从而选择最有希望的子节点进行进一步搜索,同时舍弃不可能达到最优解的子节点。
- 分支限界法常用于解决组合优化问题,其中目标是在满足一定约束条件下找到最优解或近似最优解。
- 分支限界法通过剪枝策略来减少搜索空间,提高求解效率。
# 0/1背包问题:给定一组物品的重量和价值,选择一些物品放入容量为W的背包中,使得总价值最大。
def knapsack_01(values, weights, capacity):
n = len(values)
best_value = 0
best_subset = []
def backtrack(i, cur_value, cur_weight, subset):
nonlocal best_value, best_subset
if i == n:
if cur_value > best_value:
best_value = cur_value
best_subset = subset
return
if cur_weight + weights[i] <= capacity:
# 选择当前物品
subset.append(i)
backtrack(i + 1, cur_value + values[i], cur_weight + weights[i], subset)
subset.pop()
# 不选择当前物品
backtrack(i + 1, cur_value, cur_weight, subset)
backtrack(0, 0, 0, [])
return best_value, [values[i] for i in best_subset]
# 测试
values = [10, 40, 30, 50]
weights = [5, 4, 6, 3]
capacity = 10
max_value, items = knapsack_01(values, weights, capacity)
print("Max Value:", max_value)
print("Selected Items:", items)
5.动态规划
动态规划(Dynamic Programming): 动态规划是一种将复杂问题分解为简单子问题并存储子问题的解的方法。它通过自底向上的方式逐步计算并保存子问题的解,从而避免了重复计算,提高了求解效率。
- 动态规划常用于解决需要逐步决策的问题,其中当前决策依赖于之前的决策。
- 动态规划通过存储中间结果,避免了重复计算,提高了求解效率。它通常用于求解最优化问题、序列问题、组合问题等。
# 斐波那契数列:使用动态规划计算斐波那契数列的第n个数
def fibonacci(n):
if n <= 1:
return n
dp = [0] * (n + 1)
dp[1] = 1
for i in range(2, n + 1):
dp[i] = dp[i - 1] + dp[i - 2]
return dp[n]
# 测试
n = 6
fib = fibonacci(n)
print(f"Fibonacci({n}) =", fib)