每日一记,今天开始
从今天开始每天争取自己手写一两个小程序,即使是从书上看的,或者从网上学的,都自己手动地把代码打出来,贴在这里。
培养自己这个习惯,尽最大可能坚持下来。
水滴石穿,绳锯木断。
2014年9月10日
今天学习的是:求最大子序列和
有三种算法:
1 复杂度为O(N2)
1 package findmaxsub; 2 3 //求最大子序列和算法1:相当是遍历了一遍 4 5 public class FindMaxSu { 6 7 public static void main(String[] args) { 8 // TODO Auto-generated method stub 9 int[] a = new int[] {4,-3,5,-2,-1,2,6,-2,10}; 10 System.out.println(findMax(a)); 11 12 } 13 private static int findMax(int [] array){ 14 int maxSum = 0; 15 for(int i=0;i<array.length;i++){ 16 int sum=0; 17 for(int j=i;j<array.length;j++){ 18 sum+=array[j]; 19 if(sum>maxSum){//注意这个if的位置 20 maxSum=sum; 21 } 22 } 23 } 24 return maxSum; 25 } 26 }
2 复杂度为O(NlogN)
1 package findmaxsub; 2 3 //寻找最大子序列和的算法2 4 //基本思路:最大子序列和三种情况:出现在数据的左半部分,右半部分,跨越数据的中部从而位于左右两半部分之中 5 //前两种情况用递归,后一种情况简单地用两个for循环就行了 6 7 //分而治之的思想:divide-and-conquer 8 //递归的思想 9 //关键是处理第三种情况为什么能用两个简单的循环:因为子序列的头已经确定了,必须包含这个中间的元素 10 11 public class FindMaxSub { 12 13 /** 14 * @param args 15 */ 16 public static void main(String[] args) { 17 // TODO Auto-generated method stub 18 19 int[] arr = new int[]{4,-3,5,-2,-1,2,6,-2,10}; 20 System.out.println(maxSub(arr,0,arr.length-1)); 21 22 23 } 24 25 private static int maxSub(int [] array,int left,int right){ 26 if(left==right){ 27 if (array[left]>0) 28 return array[left]; 29 else 30 return 0; 31 } 32 int center= (left+right)/2; 33 //前两种情况用递归 34 int leftMax=maxSub(array,left,center); 35 int rightMax=maxSub(array,center+1,right); 36 37 //后一种情况用两个for循环 38 int leftBorderMax=0; int leftBorderSum=0; 39 for(int i=center;i>=left;i--){ 40 leftBorderSum+=array[i]; 41 if(leftBorderSum>leftBorderMax){ 42 leftBorderMax=leftBorderSum; 43 } 44 } 45 int rightBorderMax=0; int rightBorderSum=0; 46 for(int i=center+1;i<=right;i++){ 47 rightBorderSum+=array[i]; 48 if(rightBorderSum>rightBorderMax){ 49 rightBorderMax=rightBorderSum; 50 } 51 } 52 53 return max3(leftMax,rightMax,leftBorderMax+rightBorderMax); 54 55 } 56 57 private static int max3(int a, int b, int c){ 58 int n=a>b?a:b; 59 return c>n?c:n; 60 } 61 62 }
3 复杂度为O(N)
1 package findmaxsub; 2 //求最大子序列和算法3: 3 //这个算法最巧妙,时间运行最小 4 //基于的思想:任何最大子序列的起点项不可能为负数,那么任何负的子序列不可能是最大子序列的前缀 5 //所以只要前面的累积和为负数了,就可以重新选择开头了 6 7 public class findMaxSubb { 8 9 /** 10 * @param args 11 */ 12 public static void main(String[] args) { 13 // TODO Auto-generated method stub 14 int [] arr = new int[]{4,-3,5,-2,-1,2,6,-2}; 15 System.out.println(findMax(arr)); 16 17 } 18 private static int findMax(int[] arr){ 19 int sum=0,maxSum=0; 20 for(int i=0;i<arr.length;i++){ 21 sum+=arr[i]; 22 if(sum<0) 23 sum=0; 24 if(sum>maxSum){ 25 maxSum=sum; 26 } 27 } 28 return maxSum; 29 } 30 31 }