|
| 1 | +{ |
| 2 | + "cells": [ |
| 3 | + { |
| 4 | + "cell_type": "markdown", |
| 5 | + "metadata": { |
| 6 | + "graffitiCellId": "id_7qqfnwv" |
| 7 | + }, |
| 8 | + "source": [ |
| 9 | + "### Problem Statement\n", |
| 10 | + "You are given an array `arr` having `n` integers. You have to find the maximum sum of contiguous subarray among all the possible subarrays. This problem is commonly called as [Maximum Subarray Problem](https://en.wikipedia.org/wiki/Maximum_subarray_problem). Solve this problem in *O(nlogn)* time, using Divide and Conquer approach. \n", |
| 11 | + "\n", |
| 12 | + "\n", |
| 13 | + "**Example 1**<br>\n", |
| 14 | + "Input: `arr = [-2, 1, -3, 5, 0, 3, 2, -5, 4]`<br>\n", |
| 15 | + "Output: `Maximum Sum = 10` for the `subarray = [5, 0, 3, 2]`<br>\n", |
| 16 | + "\n", |
| 17 | + "**Example 2**<br>\n", |
| 18 | + "Input: `arr = [-2, -5, 6, -2, -3, 1, 5, -6]`<br>\n", |
| 19 | + "Output: `Maximum Sum = 7` for the `subarray = [6, -2, -3, 1, 5]`<br>\n", |
| 20 | + "\n", |
| 21 | + "***As of now, let's not return the subarray itself.***" |
| 22 | + ] |
| 23 | + }, |
| 24 | + { |
| 25 | + "cell_type": "markdown", |
| 26 | + "metadata": { |
| 27 | + "graffitiCellId": "id_7dk56pg" |
| 28 | + }, |
| 29 | + "source": [ |
| 30 | + "---\n", |
| 31 | + "### The Idea\n", |
| 32 | + "Divide the given array into three subarray w.r.t. the middle, say Left, Right, and Cross subarrays. Recurse on the Left part, and Right part untill you reach the base condition, i.e. single element in a subarray. \n", |
| 33 | + "\n", |
| 34 | + "Calculate the **maximum sum** of the Left, Right, and Cross subarrays, say `L`, `R`, and `C` respectively. Return the maximum of `L`, `R`, and `C`. \n", |
| 35 | + "\n", |
| 36 | + "\n", |
| 37 | + "#### Logic to the Calculate the Maximum sum of a Cross Subarray\n", |
| 38 | + "Start from the middle index, and traverse (sum the elements) in the left direction. Keep track of the maximum sum on the left part, say `leftMaxSum`. Similarly, start from the (middle +1) index, and traverse (sum the elements) in the right direction. Keep track of the maximum sum on the right part, say `rightMaxSum`. Return the `(leftMaxSum + rightMaxSum)`, as `C`. The following exmaple would help you imagine the solution better:\n", |
| 39 | + "\n", |
| 40 | + "\n", |
| 41 | + "<img style=\"float: center;\" src=\"DNC.png\">\n", |
| 42 | + "<p style=\"text-align:center;\">The solution is 13.</p>\n", |
| 43 | + "\n", |
| 44 | + "--- \n", |
| 45 | + "### Pseudocode and Time Complexity Analysis\n", |
| 46 | + "`maxSubArrayRecursive(arr, start, stop)`     <font color=\"red\">*T(n)*</font> <br> \n", |
| 47 | + "  ` 1. if (start==stop):`<br>\n", |
| 48 | + "      `return arr[start]`<br><br>\n", |
| 49 | + "  ` 2. Calculate mid index`       <font color=\"red\">*constant*</font> <br><br>\n", |
| 50 | + "  ` 3. L = maxSubArrayRecursive(arr, start, mid) `       <font color=\"red\">*T($\\frac{n}{2}$)*</font> <br><br>\n", |
| 51 | + "  ` 4. R = maxSubArrayRecursive(arr, mid+1, stop) `       <font color=\"red\">*T($\\frac{n}{2}$)*</font> <br><br>\n", |
| 52 | + "  ` 5. C = maxCrossingSum(arr, start, mid, stop) `        <font color=\"red\">*$\\Theta(n)$*</font> <br><br>\n", |
| 53 | + "  ` 6. return max(C, max(L,R)) `       <font color=\"red\">*constant*</font> <br>\n", |
| 54 | + "<br>\n", |
| 55 | + "\n", |
| 56 | + "Total time of execution $T(n)$ = $2*T(\\frac{n}{2}) + \\Theta(n) \\equiv O(nlogn)$\n", |
| 57 | + "\n", |
| 58 | + "### Exercise - Write the function definition here. " |
| 59 | + ] |
| 60 | + }, |
| 61 | + { |
| 62 | + "cell_type": "code", |
| 63 | + "execution_count": 1, |
| 64 | + "metadata": { |
| 65 | + "graffitiCellId": "id_971xrg4" |
| 66 | + }, |
| 67 | + "outputs": [], |
| 68 | + "source": [ |
| 69 | + "# Solution\n", |
| 70 | + "\n", |
| 71 | + "'''Helper Function - Find the max crossing sum w.r.t. middle index'''\n", |
| 72 | + "def maxCrossingSum(arr, start, mid, stop):\n", |
| 73 | + " '''LEFT PHASE - Traverse the Left part starting from mid element'''\n", |
| 74 | + " leftSum = arr[mid] # Denotes the sum of left part from mid element to the current element\n", |
| 75 | + " leftMaxSum = arr[mid] # Keep track of maximum sum\n", |
| 76 | + " \n", |
| 77 | + " # Traverse in reverse direction from (mid-1) to start \n", |
| 78 | + " for i in range(mid-1, start-1, -1): # The second argument of range is not inclusive. Third argument is the step size.\n", |
| 79 | + " leftSum = leftSum + arr[i]\n", |
| 80 | + " if (leftSum > leftMaxSum): # Update leftMaxSum\n", |
| 81 | + " leftMaxSum = leftSum\n", |
| 82 | + " \n", |
| 83 | + " '''RIGHT PHASE - Traverse the Right part, starting from (mid+1)'''\n", |
| 84 | + " rightSum = arr[mid+1] # Denotes the sum of right part from (mid+1) element to the current element\n", |
| 85 | + " rightMaxSum = arr[mid+1] # Keep track of maximum sum\n", |
| 86 | + " \n", |
| 87 | + " # Traverse in forward direction from (mid+2) to stop\n", |
| 88 | + " for j in range(mid+2, stop+1): # The second argument of range is not inclusive\n", |
| 89 | + " rightSum = rightSum + arr[j]\n", |
| 90 | + " if (rightSum > rightMaxSum): # Update rightMaxSum\n", |
| 91 | + " rightMaxSum = rightSum\n", |
| 92 | + "\n", |
| 93 | + " '''Both rightMaxSum and lefttMaxSum each would contain value of atleast one element from the arr'''\n", |
| 94 | + " return (rightMaxSum + leftMaxSum)\n", |
| 95 | + "\n", |
| 96 | + "'''Recursive function'''\n", |
| 97 | + "def maxSubArrayRecursive(arr, start, stop): # start and stop are the indices\n", |
| 98 | + " # Base case\n", |
| 99 | + " if (start==stop):\n", |
| 100 | + " return arr[start]\n", |
| 101 | + "\n", |
| 102 | + " if(start < stop):\n", |
| 103 | + " mid = (start+stop)//2 # Get the middle index\n", |
| 104 | + " L = maxSubArrayRecursive(arr, start, mid) # Recurse on the Left part\n", |
| 105 | + " R = maxSubArrayRecursive(arr, mid+1, stop) # Recurse on the Right part\n", |
| 106 | + " C = maxCrossingSum(arr, start, mid, stop) # Find the max crossing sum w.r.t. middle index\n", |
| 107 | + " return max(C, max(L,R)) # Return the maximum of (L,R,C)\n", |
| 108 | + " \n", |
| 109 | + " else: # If ever start > stop. Not feasible. \n", |
| 110 | + " return nums[start]\n", |
| 111 | + "\n", |
| 112 | + "def maxSubArray(arr):\n", |
| 113 | + " start = 0 # staring index of original array\n", |
| 114 | + " stop = len(arr) -1 # ending index of original array\n", |
| 115 | + " return maxSubArrayRecursive(arr, start, stop)\n" |
| 116 | + ] |
| 117 | + }, |
| 118 | + { |
| 119 | + "cell_type": "markdown", |
| 120 | + "metadata": { |
| 121 | + "graffitiCellId": "id_ojenmxb" |
| 122 | + }, |
| 123 | + "source": [ |
| 124 | + "<span class=\"graffiti-highlight graffiti-id_ojenmxb-id_pw4giwj\"><i></i><button>Show Solution</button></span>" |
| 125 | + ] |
| 126 | + }, |
| 127 | + { |
| 128 | + "cell_type": "markdown", |
| 129 | + "metadata": { |
| 130 | + "graffitiCellId": "id_v341rpp" |
| 131 | + }, |
| 132 | + "source": [ |
| 133 | + "### Test - Let's test your function" |
| 134 | + ] |
| 135 | + }, |
| 136 | + { |
| 137 | + "cell_type": "code", |
| 138 | + "execution_count": 2, |
| 139 | + "metadata": { |
| 140 | + "graffitiCellId": "id_1wiu9yd" |
| 141 | + }, |
| 142 | + "outputs": [ |
| 143 | + { |
| 144 | + "name": "stdout", |
| 145 | + "output_type": "stream", |
| 146 | + "text": [ |
| 147 | + "Maximum Sum = 13\n" |
| 148 | + ] |
| 149 | + } |
| 150 | + ], |
| 151 | + "source": [ |
| 152 | + "# Test your code\n", |
| 153 | + "arr = [-2, 7, -6, 3, 1, -4, 5, 7] \n", |
| 154 | + "print(\"Maximum Sum = \",maxSubArray(arr)) # Outputs 13" |
| 155 | + ] |
| 156 | + }, |
| 157 | + { |
| 158 | + "cell_type": "code", |
| 159 | + "execution_count": 3, |
| 160 | + "metadata": { |
| 161 | + "graffitiCellId": "id_8kcxisn" |
| 162 | + }, |
| 163 | + "outputs": [ |
| 164 | + { |
| 165 | + "name": "stdout", |
| 166 | + "output_type": "stream", |
| 167 | + "text": [ |
| 168 | + "Maximum Sum = 6\n" |
| 169 | + ] |
| 170 | + } |
| 171 | + ], |
| 172 | + "source": [ |
| 173 | + "# Test your code\n", |
| 174 | + "arr = [-2, 1, -3, 4, -1, 2, 1, -5, 4] \n", |
| 175 | + "print(\"Maximum Sum = \",maxSubArray(arr)) # Outputs 6" |
| 176 | + ] |
| 177 | + }, |
| 178 | + { |
| 179 | + "cell_type": "code", |
| 180 | + "execution_count": 4, |
| 181 | + "metadata": { |
| 182 | + "graffitiCellId": "id_53cg7v6" |
| 183 | + }, |
| 184 | + "outputs": [ |
| 185 | + { |
| 186 | + "name": "stdout", |
| 187 | + "output_type": "stream", |
| 188 | + "text": [ |
| 189 | + "Maximum Sum = 15\n" |
| 190 | + ] |
| 191 | + } |
| 192 | + ], |
| 193 | + "source": [ |
| 194 | + "# Test your code\n", |
| 195 | + "arr = [-4, 14, -6, 7] \n", |
| 196 | + "print(\"Maximum Sum = \",maxSubArray(arr)) # Outputs 15" |
| 197 | + ] |
| 198 | + }, |
| 199 | + { |
| 200 | + "cell_type": "code", |
| 201 | + "execution_count": 5, |
| 202 | + "metadata": { |
| 203 | + "graffitiCellId": "id_876ybhp" |
| 204 | + }, |
| 205 | + "outputs": [ |
| 206 | + { |
| 207 | + "name": "stdout", |
| 208 | + "output_type": "stream", |
| 209 | + "text": [ |
| 210 | + "Maximum Sum = 10\n" |
| 211 | + ] |
| 212 | + } |
| 213 | + ], |
| 214 | + "source": [ |
| 215 | + "# Test your code\n", |
| 216 | + "arr = [-2, 1, -3, 5, 0, 3, 2, -5, 4]\n", |
| 217 | + "print(\"Maximum Sum = \",maxSubArray(arr)) # Outputs 10" |
| 218 | + ] |
| 219 | + }, |
| 220 | + { |
| 221 | + "cell_type": "code", |
| 222 | + "execution_count": 6, |
| 223 | + "metadata": { |
| 224 | + "graffitiCellId": "id_1fallee" |
| 225 | + }, |
| 226 | + "outputs": [ |
| 227 | + { |
| 228 | + "name": "stdout", |
| 229 | + "output_type": "stream", |
| 230 | + "text": [ |
| 231 | + "Maximum Sum = 7\n" |
| 232 | + ] |
| 233 | + } |
| 234 | + ], |
| 235 | + "source": [ |
| 236 | + "# Test your code\n", |
| 237 | + "arr = [-2, -5, 6, -2, -3, 1, 5, -6]\n", |
| 238 | + "print(\"Maximum Sum = \",maxSubArray(arr)) # Outputs 7" |
| 239 | + ] |
| 240 | + }, |
| 241 | + { |
| 242 | + "cell_type": "code", |
| 243 | + "execution_count": null, |
| 244 | + "metadata": { |
| 245 | + "graffitiCellId": "id_3wc4uhz" |
| 246 | + }, |
| 247 | + "outputs": [], |
| 248 | + "source": [] |
| 249 | + } |
| 250 | + ], |
| 251 | + "metadata": { |
| 252 | + "graffiti": { |
| 253 | + "firstAuthorId": "af9e0b36-2ad2-11ea-83c4-a78dc7ef519f", |
| 254 | + "id": "id_d58m4fr", |
| 255 | + "language": "EN" |
| 256 | + }, |
| 257 | + "kernelspec": { |
| 258 | + "display_name": "Python 3", |
| 259 | + "language": "python", |
| 260 | + "name": "python3" |
| 261 | + }, |
| 262 | + "language_info": { |
| 263 | + "codemirror_mode": { |
| 264 | + "name": "ipython", |
| 265 | + "version": 3 |
| 266 | + }, |
| 267 | + "file_extension": ".py", |
| 268 | + "mimetype": "text/x-python", |
| 269 | + "name": "python", |
| 270 | + "nbconvert_exporter": "python", |
| 271 | + "pygments_lexer": "ipython3", |
| 272 | + "version": "3.6.3" |
| 273 | + } |
| 274 | + }, |
| 275 | + "nbformat": 4, |
| 276 | + "nbformat_minor": 2 |
| 277 | +} |
0 commit comments