【连续】子数组之和最大并得到子数组的下标边界

来源:互联网 发布:用js写一个倒计时程序 编辑:程序博客网 时间:2024/05/29 18:37
    此博客的目的仅供个人学习和分享,其实也是为了自己复习知识方便,这也是本人第一次写博客,缺乏经验,见谅见谅!该文章主要是为了求【连续】子数组之和最大并得到子数组的下标边界,使用的算法采用的是分治的思想,分治算法的思想是将一个比较复杂的问题,分解为K个规模比较小的问题,如果这些子问题还较大,难以解决,可以再把它们分成几个更小的子问题,以此类推,直至可以直接求出解为止。这就是分治策略的基本思,想这些子问题相互独立且与原问题相同,递归解决这些子问题,就可以得到原问题的解。至于这个K是多大,一般根据情况而定,类似于插入排序的算法中一般这个K为N%2,因为一旦一个问题的元素个数为2个时,我们就能很快分出大小,但此文中这个K值并不为2,它的复杂度为N*O(logN)+N。另外欢迎大家指出不足之处!

package cn.book.exercise;



import java.util.HashMap;
import java.util.Map;


/**
 * @author Administrator
 * 寻找最适应的算法,【连续】子数组之和最大
 */
public class FindBestSubArrayTest {
public static int[] array ={-1,2,3,4,5,6,-7,8,9,33,-888888,-99999,333333,-1,-2,9};
static Map<String, Integer> map = new HashMap<String, Integer>();

public static void main(String[] args) {
System.out.println("最大的子数组之和为:"+findMaxSubArray(array, 0, array.length-1));
System.out.println("最适合的左索引值:"+map.get("leftIndex"));
System.out.println("最适合的右索引值:"+map.get("rightIndex"));
int total = 0;
for (int i = 0; i < array.length; i++) {
total += array[i];
}
System.out.println("数组的总和为:"+total);
}

/**
* @param a
* @param beginIndex
* @param endIndex

* 折半法寻找 n*logN + N
*/
public static int findMaxSubArray(int[] a,int beginIndex,int endIndex){
int leftIndex = 0, rightIndex = 0;


if (beginIndex == endIndex) {//如果只剩下一个元素
if(a[beginIndex] > 0){
return a[beginIndex];
}
return 0;
}

int leftMaxSum,rightMaxSum,totalMaxSum;
int midIndex =(beginIndex+ endIndex) /2;
/**************************************求分开的大小*************************************/
leftMaxSum = findMaxSubArray(a, beginIndex, midIndex);//分的思想,需找左边最大的值
rightMaxSum = findMaxSubArray(a, midIndex+1, endIndex);
/***********************************************************************************/

int  theLeftBorderMaxSum =0;
int theRightBorderMaxSum = 0;
/**************************************求整体的大小*************************************/
int tempSum = 0;
for (int i = midIndex; i >= beginIndex; i--) {//从左边靠近
tempSum += a[i];
if (tempSum > theLeftBorderMaxSum) {
theLeftBorderMaxSum = tempSum;
leftIndex = i;//可能适合的左索引值
}
}

tempSum = 0;//置空
for (int i = midIndex+1; i <= endIndex; i++) {//从右边靠近
tempSum += a[i];
if (tempSum > theRightBorderMaxSum) {
theRightBorderMaxSum = tempSum;
rightIndex = i;//可能适合的右索引值
}
}
//分之后就要治了
totalMaxSum = theLeftBorderMaxSum + theRightBorderMaxSum;//两边连起来的大小
int  tempMax  = max3(leftMaxSum, rightMaxSum, totalMaxSum);
/*******************************求子数组之和最大的游标边界***************************************/
if( null==  map.get("tempMax")||  tempMax > map.get("tempMax").intValue() ){//第一次赋值或者出现更大的子数组,if判断从前往后判断
if(rightMaxSum ==max3(leftMaxSum, rightMaxSum, totalMaxSum)){//如果是合并之后右边值最大
map.put("leftIndex", Integer.valueOf(midIndex+1));
map.put("rightIndex",Integer.valueOf(rightIndex));
}else if(leftMaxSum ==max3(leftMaxSum, rightMaxSum, totalMaxSum)){//如果是左边值最大
map.put("leftIndex", Integer.valueOf(leftIndex));
map.put("rightIndex",Integer.valueOf(midIndex));
}else {//如果是右边值最大
map.put("leftIndex", Integer.valueOf(leftIndex));
map.put("rightIndex",Integer.valueOf(rightIndex));
}
map.put("tempMax", tempMax);
}
return tempMax;
}

public static int max3(int a, int b , int c){
return a> b ? ((a >c)? a: c) : ((b >c)? b: c);
}
}
0 0
原创粉丝点击