From bd2635bc6e2106c36e94f868f40b0e0114471fe9 Mon Sep 17 00:00:00 2001 From: StutiTiwari <116055334+s-tuti@users.noreply.github.com> Date: Tue, 25 Jun 2024 19:40:46 +0530 Subject: [PATCH] Update dynamic-programming.md --- contrib/ds-algorithms/dynamic-programming.md | 189 +++++++++++++++++++ 1 file changed, 189 insertions(+) diff --git a/contrib/ds-algorithms/dynamic-programming.md b/contrib/ds-algorithms/dynamic-programming.md index 0f16d5c..986ecd3 100644 --- a/contrib/ds-algorithms/dynamic-programming.md +++ b/contrib/ds-algorithms/dynamic-programming.md @@ -234,3 +234,192 @@ print("Length of lis is", lis(arr)) ## Complexity Analysis - **Time Complexity**: O(n * n) for both approaches, where n is the length of the array. - **Space Complexity**: O(n * n) for the memoization table in Top-Down Approach, O(n) in Bottom-Up Approach. + +# 5. String Edit Distance + +The String Edit Distance algorithm calculates the minimum number of operations (insertions, deletions, or substitutions) required to convert one string into another. + +**Algorithm Overview:** +- **Base Cases:** If one string is empty, the edit distance is the length of the other string. +- **Memoization:** Store the results of previously computed edit distances to avoid redundant computations. +- **Recurrence Relation:** Compute the edit distance by considering insertion, deletion, and substitution operations. + +## String Edit Distance Code in Python (Top-Down Approach with Memoization) +```python +def edit_distance(str1, str2, memo={}): + m, n = len(str1), len(str2) + if (m, n) in memo: + return memo[(m, n)] + if m == 0: + return n + if n == 0: + return m + if str1[m - 1] == str2[n - 1]: + memo[(m, n)] = edit_distance(str1[:m-1], str2[:n-1], memo) + else: + memo[(m, n)] = 1 + min(edit_distance(str1, str2[:n-1], memo), # Insert + edit_distance(str1[:m-1], str2, memo), # Remove + edit_distance(str1[:m-1], str2[:n-1], memo)) # Replace + return memo[(m, n)] + +str1 = "sunday" +str2 = "saturday" +print(f"Edit Distance between '{str1}' and '{str2}' is {edit_distance(str1, str2)}.") +# Output: Edit Distance between 'sunday' and 'saturday' is 3. +``` +## String Edit Distance Code in Python (Bottom-Up Approach) +```python +def edit_distance(str1, str2): + m, n = len(str1), len(str2) + dp = [[0 for _ in range(n + 1)] for _ in range(m + 1)] + + for i in range(m + 1): + for j in range(n + 1): + if i == 0: + dp[i][j] = j + elif j == 0: + dp[i][j] = i + elif str1[i - 1] == str2[j - 1]: + dp[i][j] = dp[i - 1][j - 1] + else: + dp[i][j] = 1 + min(dp[i - 1][j], dp[i][j - 1], dp[i - 1][j - 1]) + + return dp[m][n] + +str1 = "sunday" +str2 = "saturday" +print(f"Edit Distance between '{str1}' and '{str2}' is {edit_distance(str1, str2)}.") +# Output: Edit Distance between 'sunday' and 'saturday' is 3. +``` +## **Complexity Analysis:** +- **Time Complexity:** O(m * n) where m and n are the lengths of string 1 and string 2 respectively +- **Space Complexity:** O(m * n) for both top-down and bottom-up approaches + + +# 6. Matrix Chain Multiplication + +The Matrix Chain Multiplication finds the optimal way to multiply a sequence of matrices to minimize the number of scalar multiplications. + +**Algorithm Overview:** +- **Base Cases:** The cost of multiplying one matrix is zero. +- **Memoization:** Store the results of previously computed matrix chain orders to avoid redundant computations. +- **Recurrence Relation:** Compute the optimal cost by splitting the product at different points and choosing the minimum cost. + +## Matrix Chain Multiplication Code in Python (Top-Down Approach with Memoization) +```python +def matrix_chain_order(p, memo={}): + n = len(p) - 1 + def compute_cost(i, j): + if (i, j) in memo: + return memo[(i, j)] + if i == j: + return 0 + memo[(i, j)] = float('inf') + for k in range(i, j): + q = compute_cost(i, k) + compute_cost(k + 1, j) + p[i - 1] * p[k] * p[j] + if q < memo[(i, j)]: + memo[(i, j)] = q + return memo[(i, j)] + return compute_cost(1, n) + +p = [1, 2, 3, 4] +print(f"Minimum number of multiplications is {matrix_chain_order(p)}.") +# Output: Minimum number of multiplications is 18. +``` +## Matrix Chain Multiplication Code in Python (Bottom-Up Approach) +```python +def matrix_chain_order(p): + n = len(p) - 1 + m = [[0 for _ in range(n)] for _ in range(n)] + + for L in range(2, n + 1): + for i in range(n - L + 1): + j = i + L - 1 + m[i][j] = float('inf') + for k in range(i, j): + q = m[i][k] + m[k + 1][j] + p[i] * p[k + 1] * p[j + 1] + if q < m[i][j]: + m[i][j] = q + + return m[0][n - 1] + +p = [1, 2, 3, 4] +print(f"Minimum number of multiplications is {matrix_chain_order(p)}.") +# Output: Minimum number of multiplications is 18. +``` +## **Complexity Analysis:** +- **Time Complexity:** O(n^3) where n is the number of matrices in the chain. For an `array p` of dimensions representing the matrices such that the `i-th matrix` has dimensions `p[i-1] x p[i]`, n is `len(p) - 1` +- **Space Complexity:** O(n^2) for both top-down and bottom-up approaches + + +# 7. Optimal Binary Search Tree + +The Matrix Chain Multiplication finds the optimal way to multiply a sequence of matrices to minimize the number of scalar multiplications. + +**Algorithm Overview:** +- **Base Cases:** The cost of a single key is its frequency. +- **Memoization:** Store the results of previously computed subproblems to avoid redundant computations. +- **Recurrence Relation:** Compute the optimal cost by trying each key as the root and choosing the minimum cost. + +## Optimal Binary Search Tree Code in Python (Top-Down Approach with Memoization) +```python +def optimal_bst(keys, freq, memo={}): + n = len(keys) + def compute_cost(i, j): + if (i, j) in memo: + return memo[(i, j)] + if i > j: + return 0 + if i == j: + return freq[i] + memo[(i, j)] = float('inf') + total_freq = sum(freq[i:j+1]) + for r in range(i, j + 1): + cost = (compute_cost(i, r - 1) + + compute_cost(r + 1, j) + + total_freq) + if cost < memo[(i, j)]: + memo[(i, j)] = cost + return memo[(i, j)] + return compute_cost(0, n - 1) + +keys = [10, 12, 20] +freq = [34, 8, 50] +print(f"Cost of Optimal BST is {optimal_bst(keys, freq)}.") +# Output: Cost of Optimal BST is 142. +``` +## Optimal Binary Search Tree Code in Python (Bottom-Up Approach) +```python +def optimal_bst(keys, freq): + n = len(keys) + cost = [[0 for x in range(n)] for y in range(n)] + + for i in range(n): + cost[i][i] = freq[i] + + for L in range(2, n + 1): + for i in range(n - L + 1): + j = i + L - 1 + cost[i][j] = float('inf') + total_freq = sum(freq[i:j+1]) + for r in range(i, j + 1): + c = (cost[i][r - 1] if r > i else 0) + \ + (cost[r + 1][j] if r < j else 0) + \ + total_freq + if c < cost[i][j]: + cost[i][j] = c + + return cost[0][n - 1] + +keys = [10, 12, 20] +freq = [34, 8, 50] +print(f"Cost of Optimal BST is {optimal_bst(keys, freq)}.") +# Output: Cost of Optimal BST is 142. +``` +## **Complexity Analysis:** +- **Time Complexity:** O(n^3) where n is the number of keys in the binary search tree. +- **Space Complexity:** O(n^2) for both top-down and bottom-up approaches + +
+
+