《算法导论》学习笔记——寻找最大子数组
2015-01-19 13:41
316 查看
寻找最大子数组
1.问题描述
给定一个数组A,找到数组A的一个子数组使得该子数组内所有元素的和最大。当然,如果A中的元素恒为正或恒为负,那么A的最大子数组即为A自身或A中最大的负数,这是很简单的情况。但如果A中的元素有正有负,问题就比较复杂。如下面的数组A,其最大子数组应该为{18,20,-7,12}。如果采用暴力求解法,那么需要我们至少需要检查n(n-1)/2,即组合数Cn2,所以暴力求解法的算法复杂度为O(n2)(n2:n*n,即n的平方)。所以我们采用一种较好的方法来求解最大子数组——分治法。
2.使用分治策略求解最大子数组
假设我们要寻找数组A[low...high]的最大子数组,分治法的策略即为我们要将数组尽量等分为两个规模一样的数组,因此。可以找到数组的中间位置mid,然后求解两个子数组A[low...mid]和A[mid+1...high]。如下图所示,A[low...high]的任何连续子数组A[i...j]必然属于下列情况:- 完全位于子数组A[low...mid]中,因此low <= i <= j <= mid;
- 完全位于子数组A[mid+1...high]中,因此mid < i <= j <= high;
- 跨域了中点mid,因此low <= i <= mid < j <= high.
因此,A[low...high]的最大子数组必然属于上述三种情况之一,对于前两种情况,我们只需采用分治策略递归地求解最大子数组即可;我们要思考的只是对于跨域中点的子数组的求解以及在这三种情况中选取最大的子数组。这也是容易求得的,根据上面的分析,任何跨越了中点的子数组都是由两个子数组A[low...mid]和A[mid+1...high]组成,且满足条件low <= i <= mid < j <= high。因此,我们只需要找出形如A[low...mid]和A[mid+1...high]的最大子数组,然后将其合并即可。
最后对算法复杂度进行评价:采用分治策略求解最大子数组的算法复杂度为O(nlogn)。
3.代码实现(C,Java,Python)
C
#include <stdio.h> #include <stdlib.h> #include <limits.h> typedef struct { int left; int right; int sum; }Subarray; Subarray subarray; Subarray findMaxCrossSubarray(int* array, int low, int mid, int high) { int i, left_sum , right_sum; left_sum = right_sum = INT_MIN; Subarray subarray_cross; subarray_cross.sum = 0; for(i = mid; i >= low; i--) { subarray_cross.sum += array[i]; if(subarray_cross.sum > left_sum) { left_sum = subarray_cross.sum; subarray_cross.left = i; } } subarray_cross.sum = 0; for(i = mid + 1; i <= high; i++) { subarray_cross.sum += array[i]; if(subarray_cross.sum > right_sum) { right_sum = subarray_cross.sum; subarray_cross.right = i; } } subarray_cross.sum = left_sum + right_sum; return subarray_cross; } Subarray findMaxSubarray(int* array, int low, int high) { int mid; Subarray subarray_left; Subarray subarray_right; Subarray subarray_cross; if(low == high) { subarray.left = low; subarray.right = high; subarray.sum = array[low]; return subarray; } else { mid = (low + high) / 2; subarray_left = findMaxSubarray(array, low, mid); subarray_right = findMaxSubarray(array, mid + 1, high); subarray_cross = findMaxCrossSubarray(array, low, mid, high); if(subarray_left.sum > subarray_right.sum && subarray_left.sum > subarray_cross.sum) return subarray_left; else if(subarray_right.sum > subarray_left.sum && subarray_right.sum > subarray_cross.sum) return subarray_right; else return subarray_cross; } } int main() { int *array, len, i; printf("Enter the length of the array: "); scanf("%d", &len); array = (int* )malloc(len * sizeof(int)); for(i = 0; i < len; i++) scanf("%d", &array[i]); subarray = findMaxSubarray(array, 0, len - 1); printf("The index of the maximum subarray form %d to %d, and the sum is %d.\n", \ subarray.left + 1, subarray.right + 1, subarray.sum); printf("The maximum subarry is consist of: "); for(i = subarray.left; i <= subarray.right; i++) printf("%d ", array[i]); return 0; }
Java
import java.util.*; public class FindMaxSubarray { public static void main(String[] args){ Scanner in = new Scanner(System.in); ArrayList<Integer> array = new ArrayList<Integer>(); HashMap<String, Integer> subarray = new HashMap<String, Integer>(); System.out.print("Enter the length of array: "); int length = in.nextInt(); System.out.print("Enter the elements of array: "); for(int i = 0; i < length; i++) array.add(in.nextInt()); in.close(); Find find = new Find(array); subarray = find.findSubArray(find.getLow(), find.getHigh()); System.out.print("The value of the maximum subarray is " + subarray.get("sum") + " , from the index " + (subarray.get("low") + 1) + " to the index " + (subarray.get("high") + 1) + "."); System.out.print("The elements of the maximum subarray are: "); for(int i = subarray.get("low"); i <= subarray.get("high"); i++) System.out.print(array.get(i) + " "); System.out.print("."); } } class Find{ public Find(ArrayList<Integer> array) { this.array = array; } public HashMap<String, Integer> findSubArray(int low, int high){ if (low == high){ subarray.put("low", low); subarray.put("high", high); subarray.put("sum", array.get(low)); return subarray; } else { int mid = (low + high) / 2; subarrayLeft = findSubArray(low, mid); subarrayRight = findSubArray(mid + 1, high); subarrayCross = findMaxCrossSubarray(low, mid, high); if (subarrayLeft.get("sum") >= subarrayRight.get("sum") && subarrayLeft.get("sum") >= subarrayCross.get("sum")){ return subarrayLeft; } else if (subarrayRight.get("sum") >= subarrayLeft.get("sum") && subarrayRight.get("sum") >= subarrayCross.get("sum")){ return subarrayRight; } else { return subarrayCross; } } } public HashMap<String, Integer> findMaxCrossSubarray(int low, int mid, int high){ int sum = 0; int leftSum = Integer.MIN_VALUE; int maxLeft = 0; for (int i = mid; i >= low; i--){ sum += array.get(i); if (sum > leftSum){ leftSum = sum; maxLeft = i; } } int rightSum = Integer.MIN_VALUE; int maxRight = 0; sum = 0; for (int i = mid + 1; i <= high; i++){ sum += array.get(i); if (sum > rightSum){ rightSum = sum; maxRight = i; } } subarray.put("low", maxLeft); subarray.put("high", maxRight); subarray.put("sum", leftSum + rightSum); return subarray; } public int getLow(){ return 0; } public int getHigh(){ return array.size() - 1; } private ArrayList<Integer> array; private HashMap<String, Integer> subarray = new HashMap<String, Integer>(); private HashMap<String, Integer> subarrayLeft = new HashMap<String, Integer>(); private HashMap<String, Integer> subarrayRight = new HashMap<String, Integer>(); private HashMap<String, Integer> subarrayCross = new HashMap<String, Integer>(); }
Python
findMaxSubarray.pyimport sys def findMaxSubarray(array, low, high): if low == high: subarray = {"low": low, "high": high, "sum": array[low]} return subarray else: mid = (low + high) / 2 subarrayLeft = findMaxSubarray(array, low, mid) subarrayRight = findMaxSubarray(array, mid + 1, high) subarrayCross = findMaxCrossSubarray(array, low, mid, high) if subarrayLeft["sum"] > subarrayRight["sum"] and subarrayLeft["sum"] > subarrayCross["sum"]: return subarrayLeft elif subarrayRight["sum"] > subarrayLeft["sum"] and subarrayRight["sum"] > subarrayCross["sum"]: return subarrayRight else: return subarrayCross def findMaxCrossSubarray(array, low, mid, high): sum = 0; leftSum = sys.maxint * -1 maxLeft = 0 for i in range(mid, low, -1): sum += array[i]; if sum > leftSum : leftSum = sum maxLeft = i sum = 0; RightSum = sys.maxint * -1 maxRight = 0 for i in range(mid + 1, high): sum += array[i]; if sum > RightSum : RightSum = sum maxRight = i crossSubArray = {"low": maxLeft, "high": maxRight, "sum": leftSum + RightSum} return crossSubArray
test.py
import findMaxSubarray array = [13, -3, -25, 20, -3, -16, -23, 18, 20, -7, 12, -5, -22, 15, -4, 7] length = len(array) - 1 subarray = [] maxSubarray = findMaxSubarray.findMaxSubarray(array, 0, length) print "The maximum of subarray is " + str(maxSubarray["sum"]) + \ " from index " + str(maxSubarray["low"] + 1) + \ " to index " + str(maxSubarray["high"] + 1) + "." for i in range(maxSubarray["low"], maxSubarray["high"] + 1): subarray.append(array[i]) print "The elements of the maximum subarry are " + str(subarray) + "."
相关文章推荐
- 《编程之美》学习笔记——2.10寻找数组中的最大值和最小值
- 《算法导论》学习笔记——最大子数组(分治策略,动态规划)
- 算法导论4.1DivideAndConquer寻找最大子数组
- 《算法导论》学习笔记之最大子数组问题
- 《算法导论》学习笔记(2):最大子数组
- 编程之美2.10寻找数组中的最大值和最小值代码
- [ALGO-49] 寻找数组中最大值
- 分治法解决寻找数组中最大最小值的问题
- 寻找数组中的最大值最小值问题
- 算法导论笔记:04最大子数组矩阵乘法以及递归式求解
- 寻找数组中的最大值和最小值
- 蓝桥杯习题集_ 算法训练 寻找数组中最大值
- 算法训练 寻找数组中最大值
- 算法导论,分治策略,最大子数组
- 寻找数组中和最大的子序列
- 2.10 寻找数组中的最大值和最小值
- [ALGO-49] 寻找数组中最大值
- 编程之美2.10 寻找数组中的最大值和最小值
- 数据结构——算法之(041)(寻找数组中的最大值和最小值)
- 寻找数组中的最大连续子串