JavaScript 子数组最大和
在 JavaScript 中寻找子数组的最大和对于寻求优化算法效率并揭示数据集隐藏潜力的开发者来说,是一项至关重要的任务。在计算问题解决领域,识别和计算数组内子集的最大累加和,是解锁洞察力并推动有效决策过程的关键。本文将深入探讨解决这一复杂挑战所需的方法和技术,并使用多种鲜为人知的词汇来阐明 JavaScript 编程的细微之处。通过深入研究这个主题,读者将获得驾驭复杂数据结构并释放 JavaScript 应用程序全部潜力的能力。
问题陈述
目标是设计一种高效的算法,能够有效地识别具有最大求和的子数组,同时考虑到常用术语的匮乏。为了阐明这一点,假设我们有一个包含整数元素的输入数组
[-3, 4, 2, -1, 6, -5, 3, -2, 7, 1]
期望的结果是从任何连续子数组中获得的最大和,在本例中为
15
方法
在本文中,我们将看到多种在 JavaScript 中解决上述问题陈述的方法:
暴力法
动态规划
分治法
前缀和
方法 1:暴力法
在暴力法中,我们生成所有可能的子数组并计算每个子数组的和。我们将 maxSum 设置为 -Infinity 以跟踪遇到的最大和。使用三个嵌套循环,外循环迭代起始索引,中间循环迭代结束索引,内循环通过从起始索引迭代到结束索引来计算子数组的和。
示例
findMaxSubarraySumBruteForce 函数接受一个数组 arr 作为输入,并将 maxSum 初始化为 -Infinity。它使用三个嵌套循环来生成所有可能的子数组:外循环用于起始索引,中间循环用于结束索引,内循环用于计算总和。每当找到更大的和时,最大和就会更新。最后,函数返回最大和。
function findMaxSubarraySumBruteForce(arr) { let maxSum = -Infinity; for (let i = 0; i < arr.length; i++) { for (let j = i; j < arr.length; j++) { let sum = 0; for (let k = i; k <= j; k++) { sum += arr[k]; } maxSum = Math.max(maxSum, sum); } } return maxSum; } const arr = [-3, 4, 2, -1, 6, -5, 3, -2, 7, 1]; console.log(findMaxSubarraySumBruteForce(arr));
输出
以下是控制台输出:
15
方法 2:动态规划(Kadane 算法)
Kadane 算法是一种高效的动态规划方法,可以单次遍历数组找到子数组的最大和。它使用两个变量 maxSoFar 和 maxEndingHere 来跟踪遇到的最大和。从第二个元素开始,我们遍历数组,通过取当前元素和当前元素与 maxEndingHere 之和中的最大值来更新 maxEndingHere。我们通过取之前的 maxSoFar 和更新后的 maxEndingHere 之间的最大值来更新 maxSoFar。遍历整个数组后,maxSoFar 包含子数组的最大和,然后将其返回。
示例
findMaxSubarraySumKadane 函数接受一个数组 arr 作为输入,并初始化 maxSoFar 和 maxEndingHere 变量。它遍历数组,通过比较当前元素和当前元素与 maxEndingHere 的和来更新 maxEndingHere。它还通过比较之前的 maxSoFar 和更新后的 maxEndingHere 来更新 maxSoFar。迭代完成后,函数返回存储在 maxSoFar 变量中的最大子数组和。
function findMaxSubarraySumKadane(arr) { let maxSoFar = arr[0]; let maxEndingHere = arr[0]; for (let i = 1; i < arr.length; i++) { maxEndingHere = Math.max(arr[i], maxEndingHere + arr[i]); maxSoFar = Math.max(maxSoFar, maxEndingHere); } return maxSoFar; } const arr = [-3, 4, 2, -1, 6, -5, 3, -2, 7, 1]; console.log(findMaxSubarraySumKadane(arr));
输出
以下是控制台输出:
15
方法 3:分治法
在查找最大子数组和的分治法中,数组被递归地分割成更小的子数组。findMaxSubarraySumDivideAndConquer 函数接受一个数组、一个低索引和一个高索引。如果低索引等于高索引,则它返回单个元素作为最大子数组和。中间索引计算为低索引和高索引平均值的向下取整值。该函数被递归调用以查找数组左右两半中的最大子数组和。findMaxCrossingSum 函数也被调用以查找跨越中间元素的最大子数组和。返回左、右和交叉和中的最大值。findMaxCrossingSum 函数接受一个数组、一个低索引、一个中间索引和一个高索引。它通过跟踪左侧和右侧的最大和来计算跨越中间元素的最大子数组和。左和右和的和作为跨越中间元素的最大和返回。
示例
findMaxSubarraySumDivideAndConquer 函数接受一个数组 arr、一个低索引和一个高索引作为输入。如果低索引等于高索引,则它返回该元素作为最大子数组和。该函数查找中间索引,递归调用自身以查找数组左右两半中的最大子数组和,并调用 findMaxCrossingSum 函数以查找跨越中间元素的最大和。最后,它返回三个和中的最大值。findMaxCrossingSum 函数接受一个数组 arr、一个低索引、一个中间索引和一个高索引作为输入。它计算左侧和右侧的最大和,并返回两者的和,表示跨越中间元素的最大和。
function findMaxSubarraySumDivideAndConquer(arr, low, high) { if (low === high) { return arr[low]; } const mid = Math.floor((low + high) / 2); const maxLeft = findMaxSubarraySumDivideAndConquer(arr, low, mid); const maxRight = findMaxSubarraySumDivideAndConquer(arr, mid + 1, high); const maxCrossing = findMaxCrossingSum(arr, low, mid, high); return Math.max(maxLeft, maxRight, maxCrossing); } function findMaxCrossingSum(arr, low, mid, high) { let leftSum = -Infinity; let sum = 0; for (let i = mid; i >= low; i--) { sum += arr[i]; if (sum > leftSum) { leftSum = sum; } } let rightSum = -Infinity; sum = 0; for (let i = mid + 1; i <= high; i++) { sum += arr[i]; if (sum > rightSum) { rightSum = sum; } } return leftSum + rightSum; } const arr = [-3, 4, 2, -1, 6, -5, 3, -2, 7, 1]; console.log(findMaxSubarraySumDivideAndConquer(arr,0,arr.length-1));
输出
以下是控制台输出:
15
方法 4:前缀和
前缀和方法包括计算数组的前缀和,并利用最小前缀和的概念来查找子数组的最大和。我们将 maxSum 初始化为 -Infinity 以跟踪遇到的最大和,并将 minPrefixSum 和 prefixSum 变量用于跟踪最小前缀和和当前前缀和。我们遍历数组,更新 prefixSum、maxSum 和 minPrefixSum。我们返回 maxSum 作为子数组的最大和。
示例
findMaxSubarraySumPrefixSum 函数接受一个数组 arr 作为输入,并初始化变量以跟踪遇到的最大和、最小前缀和和当前前缀和。它遍历数组,更新前缀和并通过取前缀和与最小前缀和之间的差来计算最大和。最小前缀和也会更新。最后,返回最大和。
function findMaxSubarraySumPrefixSum(arr) { let maxSum = -Infinity; let minPrefixSum = 0; let prefixSum = 0; for (let i = 0; i < arr.length; i++) { prefixSum += arr[i]; maxSum = Math.max(maxSum, prefixSum - minPrefixSum); minPrefixSum = Math.min(minPrefixSum, prefixSum); } return maxSum; } const arr = [-3, 4, 2, -1, 6, -5, 3, -2, 7, 1]; console.log(findMaxSubarraySumPrefixSum(arr));
输出
以下是控制台输出:
15
结论
最后,在 JavaScript 中寻找子数组最大和的探索揭示了一系列引人入胜的技术和算法。这项复杂的任务需要精明的数学计算和熟练的编码技巧。通过深入研究这些鲜为人知的方法,开发人员可以提高他们的熟练程度,并在解决复杂的数组相关挑战方面开辟新的可能性。掌握这些深奥的方法使程序员能够解开复杂的子数组模式并获得优化的解决方案。总之,在 JavaScript 中认真实施这些稀有的策略拓宽了问题解决的视野,并为子数组最大和难题的创新解决方案铺平了道路。