📅  最后修改于: 2023-12-03 15:42:18.166000             🧑  作者: Mango
This chapter covers topics related to the design and analysis of algorithms such as dynamic programming, greedy algorithms, etc. It also includes problems related to graph algorithms, string algorithms, and computational geometry.
Dynamic Programming is a technique where problems are broken down into smaller subproblems, and their solutions are stored in memory. This technique is useful when the same subproblem needs to be solved multiple times. Dynamic Programming can be used in problems such as the Knapsack problem, Longest Common Subsequence, and many more.
Here's an example of dynamic programming code for the Knapsack problem:
def knapsack(W, wt, val, n):
# initialize dp table
k = [[0 for _ in range(W+1)] for _ in range(n+1)]
# fill in dp table
for i in range(n+1):
for w in range(W+1):
if i == 0 or w == 0:
k[i][w] = 0
elif wt[i-1] <= w:
k[i][w] = max(val[i-1] + k[i-1][w-wt[i-1]], k[i-1][w])
else:
k[i][w] = k[i-1][w]
return k[n][W]
Greedy Algorithms are used to find the optimal solution for a problem at each stage of the algorithm. The solution is found by selecting the best local option available, which may not necessarily lead to the best global solution. Greedy Algorithms can be used in problems such as Huffman Coding, Minimum Spanning Trees, and many more.
Here's an example of a greedy algorithm code for Huffman coding:
from heapq import heappush, heappop, heapify
from collections import defaultdict
def huffman_encoding(data):
freq = defaultdict(int)
for d in data:
freq[d] += 1
heap = [[f, [s, ""]] for s, f in freq.items()]
heapify(heap)
while len(heap) > 1:
low = heappop(heap)
high = heappop(heap)
for pair in low[1:]:
pair[1] = "0" + pair[1]
for pair in high[1:]:
pair[1] = "1" + pair[1]
heappush(heap, [low[0] + high[0]] + low[1:] + high[1:])
return dict(heappop(heap)[1:])
Graph Algorithms deal with algorithms that operate on graphs. Graphs are used to represent relationships between objects, where the objects are represented as nodes, and the relationships are represented as edges. Graph algorithms can be used in problems such as Dijkstra's shortest path algorithm, Minimum Spanning Trees, etc.
Here's an example of a graph algorithm code for Dijkstra's shortest path algorithm:
import heapq
def dijkstra(graph, start):
queue, seen, mins = [(0, start)], set(), {start: 0}
while queue:
(cost, node) = heapq.heappop(queue)
if node not in seen:
seen.add(node)
for c, j in graph.get(node, {}).items():
candidate = mins.get(node, 0) + c
if j not in mins or candidate < mins[j]:
mins[j] = candidate
heapq.heappush(queue, (candidate, j))
return mins
String Algorithms deal with algorithms related to string manipulation and processing. String algorithms can be used in problems such as pattern matching, text compression, and many more.
Here's an example of a string algorithm code for pattern matching using the Knuth-Morris-Pratt algorithm:
def kmp(pattern, text):
n, m = len(text), len(pattern)
lps = [0] * m
i, j = 0, 0
while i < n:
if pattern[j] == text[i]:
i += 1
j += 1
if j == m:
return i-m
elif i < n and pattern[j] != text[i]:
if j != 0:
j = lps[j-1]
else:
i += 1
# compute lps
if j > 0 and pattern[j] != text[i]:
j = lps[j-1]
elif pattern[j] == text[i]:
lps[j] = j+1
i += 1
j += 1
return -1
Computational Geometry deal with algorithms related to geometric objects. Computational Geometry can be used in problems such as finding the convex hull, line segment intersection, and many more.
Here's an example of a computational geometry code for finding the area of a polygon using the shoelace formula:
def polygon_area(poly):
n = len(poly)
area = 0.0
for i in range(n):
j = (i + 1) % n
area += poly[i][0] * poly[j][1]
area -= poly[j][0] * poly[i][1]
area /= 2.0
return abs(area)
Overall, this chapter covers a wide range of algorithms that are essential for any programmer. From dynamic programming to computational geometry, these algorithms are widely used in many practical applications.