Realize the Dynamic Programming Algorithm of Maximum Subarray Sum with JavaScript

Dynamic programming (Dynamic Programming) is an algorithmic idea that solves complex problems by decomposing the problem into sub-problems. The core idea of ​​the dynamic programming algorithm is to decompose the problem into overlapping sub-problems, and avoid repeated calculations by storing and reusing the results of the solved sub-problems, thereby improving the efficiency of the algorithm. Dynamic programming algorithms are widely used, including shortest path problem, knapsack problem, edit distance, etc.

A dynamic programming algorithm usually requires three steps: defining states, defining state transition equations, and initial states. Next, we use an example to illustrate the specific application of the dynamic programming algorithm.

Suppose we have an array arr, which stores some numbers. We want to find a non-empty subarray such that the sum of this subarray is the largest. For example, for the array [-2,1,-3,4,-1,2,1,-5,4], we want to find a subarray such that the sum of this subarray is the largest.

We can use a dynamic programming algorithm to solve this problem. First, we define state dp[i] as the largest sum of subarrays ending in arr[i]. Next, we define the state transition equation as dp[i] = max(dp[i-1]+arr[i], arr[i]), that is, the maximum subarray sum ending with arr[i], either arr[i-1] is the ending maximum subarray sum plus arr[i], or arr[i] itself. Finally, we need to find the maximum value among all dp[i].

Next is the code to implement this dynamic programming algorithm using JavaScript:

function maxSubArray(arr) {
    
    
  const n = arr.length;
  const dp = new Array(n);
  dp[0] = arr[0];
  let max = dp[0];
  for (let i = 1; i < n; i++) {
    
    
    dp[i] = Math.max(dp[i - 1] + arr[i], arr[i]);
    max = Math.max(max, dp[i]);
  }
  return max;
}

const arr = [-2,1,-3,4,-1,2,1,-5,4];
console.log(maxSubArray(arr)); // 输出6,对应的最大子数组为[4,-1,2,1]

In this code, we first define the array dp, and then initialize dp[0] to arr[0]. Next, we traverse the entire array arr, and update dp[i] according to the defined state transition equation. At the same time, we also maintain a variable max, which is used to record the maximum value of all dp[i]. Finally, we return max.

This is an example of implementing a dynamic programming algorithm using JavaScript. Of course, in practical applications, we also need to consider some edge cases and optimizations.

  1. borderline case

When using the dynamic programming algorithm, we need to consider some boundary cases to ensure the correctness of the algorithm. In this example, if the length of the array arr is 0, then there is no sub-array, just return 0 directly. In addition, if the length of the array arr is 1, the maximum subarray sum is arr[0].

The following is an improved implementation of the code:

function maxSubArray(arr) {
    
    
  const n = arr.length;
  if (n === 0) return 0;
  if (n === 1) return arr[0];
  const dp = new Array(n);
  dp[0] = arr[0];
  let max = dp[0];
  for (let i = 1; i < n; i++) {
    
    
    dp[i] = Math.max(dp[i - 1] + arr[i], arr[i]);
    max = Math.max(max, dp[i]);
  }
  return max;
}
  1. space optimization

In the above code, we use an array dp of length n to store the state, and then update the array dp when the state transitions. This method requires the use of additional space, which is not conducive to optimization. We can reduce the space used by scrolling the array.

The idea of ​​​​rolling the array is to use only an array of length 2 to store the values ​​​​of the current state and the previous state. Every time we update the state, we can first update the value of the current state, and then update the value of the previous state. In this way, space optimization can be achieved.

The following is an improved implementation of the code:

function maxSubArray(arr) {
    
    
  const n = arr.length;
  if (n === 0) return 0;
  if (n === 1) return arr[0];
  let cur = arr[0];
  let pre = 0;
  let max = cur;
  for (let i = 1; i < n; i++) {
    
    
    pre = cur;
    cur = Math.max(pre + arr[i], arr[i]);
    max = Math.max(max, cur);
  }
  return max;
}

In this improved code, we use two variables cur and pre, representing the value of the current state and the previous state respectively. Every time we update the state, we first assign cur to pre, and then update the value of cur. In this way, we can achieve space optimization.

Guess you like

Origin blog.csdn.net/qq_29669259/article/details/129985604