题目:返回一个整数数组中最大子数组的和。
Posted 如果我什么都不会,该怎样?
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了题目:返回一个整数数组中最大子数组的和。相关的知识,希望对你有一定的参考价值。
提示:图片如果看不全右键打开图片
3月7号
我的想法:
a数组由正负数组成,创建一个数组,对应已知的a整数数组,正为1负为-1,一一对应,创建一个只含1与-1的数组称为b,然后a对应b创建数组c,对应b邻近的都为1和邻近都为-1的a中相应的整数数加起来变为c数组,c数组有前面的方法创建b1,
此时b1必为1与-1相间的数组,我代码的量就做到这里。
接下来的思路:
此时的:数组b1假设为(1,-1,1,-1,1)
3月8号:
查阅了《算法导论》这本书,书中第38页介绍的这个问题,书上的讲得是分而治之的方法。
但并不是O(n),但是课后习题4.15提出了解决方案:
3月9号晚:
这个方法一开始是看不懂的,然后我在网上查到了源码答案,然后琢磨了20多分钟终于弄明白了。
以图片的形式表示出来:
我在从数学的角度解释一下,把整数数组可以分为有限个块(因为数组是有限的),求有限个块的各自的和sum,然后最大和子数组是这些有限个块中一员;
这个最大和子数组也是由有限个块组成的,但是它有一个不变也是最重要的特征:它是由一个sum为连续的非负数的最大块和一个非负数的数字组合成的,或者只是一个非负数。
具体方法讲解:上面图片应该就是基本的步骤
设置一个int max纪录当前已知最大的,从数组中从左到右(从右到左一样)依次选出元素放入一个块中,设置sum为块中整数和(初始为0),max最初设为(二声)什么无所谓,就设为0。(有一种可以存在数组中都为非正数的情况,需要特殊求解,找出最小非正数就为最大和子数组)
从数组中取出第一个数字,(①②不是步骤而是情况,如果是步骤我会指出。而且后面的正数情况包括此数为0,也就是说我把此数为0的情况归为此数为正数的情况,即使把0的情况归給负数情况也一样,不影响)
实例步骤解析
第一步:
①为正数,加入块中,sum=sum+此数 此时块中元素有一个正数,sum>0。
②为负数,加入块中,sum=sum+此数,sum<0了,重置块,此时块中无元素,sum=0。为什么呢?因为我们上面所说的特征,此时不满足这个特征。
判断此时sum与max,如果sum大于max,max=sum(每一步之后都得判断)
第二步:
①为正数,加入块中,sum=sum+此数 当第一步为①此时块中元素有俩个正数,sum>0;当第一步为②此时块中元素只有一个正数,sum>0。
②为负数,加入块中,sum=sum+此数,当第一步是②sum<0了,重置块,此时块中无元素;sum=0,当第一步为①时,此时sum=sum+此数,sum>0,sum不变,sum<0时sum=0。
判断此时sum与max,如果sum大于max,max=sum
第三步:
重复第二步类似的步骤
.
.
..
.
直到最后一个元素进入。
此时输出max就是最大和子数组的和。
它的特征:它是由一个sum为连续的非负数的最大块和一个非负数的数字组合成的,或者只是一个非负数。
说真的我感觉我自己也说不明白,我不会讲,但是我自己明白了。但是我告诉你这个特征,这个特征我自己总结的,觉得这个特征就是解题所在。
代码:
1 int max_int_Array(int a[]) 2 { 3 int sum=0; 4 int max=0; 5 for(int i=0;i<a.length;i++) 6 { 7 sum=sum+a[i]; 8 if(sum<0) 9 { 10 sum=0; 11 } 12 if(sum>max) 13 { 14 max=sum; 15 } 16 } 17 if(sum==0) 18 { 19 max=a[0]; 20 for(int i=1;i<5;i++) 21 { 22 if(max<a[i]) 23 { 24 max=a[i]; 25 } 26 } 27 } 28 return max; 29 30 }
在网上也可以找到这个代码,这是我写的。我就是借鉴的《算法导论》习题4.15的答案,不看答案我看不懂他那个方法,但是我发现最大和子数组的特征时,我就看懂了。
总结:
上课时的思路就是错的,没有找到解题的关键(最大和子数组的特征),后来开窍了,弄明白了。
使用以前学习过Integer类,能够处理大数。把原先的返回值改为Intger,把里面的sum,max定义为Intger。
文件读取在写一个函数把文件中数字存入用List封装的Integer的数组或者创建一个Integer_(类名字自定)类里面有一个元素Integer,然后使用List<INteger_>定义一个List数组来操作。(只是Integer数组的话太难赋值了,我不喜欢)
今日错误txt读取数字时程序一直运行,我都不知道哪出错。
3月10号早,上述问题已解决。
判断是否为数字返回错误的函数:
1 boolean isNumeric00(String str) 2 { 3 try{ 4 Integer.parseInt(str); 5 return true; 6 }catch(NumberFormatException e) 7 { 8 System.err.println("异常:\\"" + str + "\\"不是数字/整数..."); 9 return false; 10 } 11 }
因为数太大改成了用正则表达式来判断,函数改为:(三月十四号改)而且不能使用LIst太浪费空间了,改为取一个数执行一次,最简化,使用BigInteger类可以数无限大。
boolean isNumeric(String str){ Pattern pattern = Pattern.compile("-[0-9]+(.[0-9]+)?|[0-9]+(.[0-9]+)?"); Matcher isNum = pattern.matcher(str); if( !isNum.matches() ){ return false; } return true; }
static BigInteger wenjian(String b) { boolean flag=true; final BigInteger min =new BigInteger("0"); BigInteger sum =new BigInteger("0"); BigInteger max =new BigInteger("0"); try // 建立一个对象,它把文件内容转成计算机能读懂的语言 { Scanner shuru = new Scanner(new BufferedReader(new FileReader(b))); String a; //网友推荐更加简洁的写法 while ((shuru.hasNext())) { // 一次读入一个数据 a=shuru.next(); //判断是否为数字 if(isNumeric(a)) { BigInteger c =new BigInteger(a); sum=sum.add(c); //compareTo方法来比较,小于则返回-1,等于则返回0,大于则返回1 //a1.compareTo(a2) if((sum.compareTo(min)==-1)) { sum=min; } if(sum.compareTo(max)==1) { max=sum; } } else { flag=false; } } shuru.close(); } catch (IOException e) { e.printStackTrace(); } if(flag==true) { return max; } else { System.err.println("文件格式有错误,退出"); return null; } }
上面这俩个是改进后的全部函数。
文件读取函数:
1 ArrayList<String> wenjian(String b) 2 { 3 ArrayList<String> list = new ArrayList<String>(); 4 boolean flag=true; 5 try // 建立一个对象,它把文件内容转成计算机能读懂的语言 6 { 7 Scanner shuru = new Scanner(new BufferedReader(new FileReader(b))); 8 String a; 9 //网友推荐更加简洁的写法 10 while ((shuru.hasNext()) ) { 11 // 一次读入一行数据 12 a=shuru.next(); 13 if(isNumeric00(a)) 14 { 15 list.add(a); 16 } 17 else 18 { 19 flag=false; 20 } 21 22 } 23 shuru.close(); 24 } catch (IOException e) { 25 26 e.printStackTrace(); 27 } 28 if(flag==true) 29 { 30 return list; 31 } 32 else 33 { 34 System.err.println("文件格式有错误"); 35 return null; 36 } 37 38 }
将String数组转化为Integer数组:
1 ArrayList<Integer> String_To_Integer(ArrayList<String> list) 2 { 3 ArrayList<Integer> list1 = new ArrayList<Integer>(); 4 for(int i=0;i<list.size();i++) 5 { 6 Integer integer =new Integer(list.get(i)); 7 list1.add(integer); 8 } 9 return list1; 10 11 }
计算最大和整数组:
Integer max_int_Array(ArrayList<Integer> b) { Integer sum=0; Integer max=0; for(int i=0;i<b.size();i++) { sum=sum+b.get(i); if(sum<0) { sum=0; } if(sum>max) { max=sum; } } if(sum==0) { max=b.get(0); for(int i=1;i<b.size();i++) { if(max<b.get(i)) { max=b.get(i); } } } return max; }
结果如下:
总结:
把问题分部,第一步读取,然后读取中得判断读出来的是不是都是数字(查阅后引用的捕捉异常的函数),第二步把读取出的String转化为Integer,第三步求最大和数组的和。
分析问题:
如果是二维数组,那么它的最大和子数组必是一个规则的长方形或特殊长方形(正方形)。特征:它肯定是一个非负数的长方形或者一个非负数的连续最大长方形加上一个非负数的偏小非负数的长方形。
把每一行看成一个块的话,那么就成了一个只有块的一维数组。在块中由上面的方法处理,找出每个块的最大和子数组,然后根据这几个最大和子数组来上下加入块来求取二维数组的最大和子数组。
分步:第一步读取文件,第二步转化,第三步求最大和子数组。
遇到的第一个问题是,如果这一行里有俩个最大和数组呢?
解决方法:
定义一个类来封装起始的行列号和终末的行列号:
public class Array_i_max {
int i;
int i_end;
int j_end;
int j;
Integer sum=0;
public int getI() {
return i;
}
public void setI(int i) {
this.i = i;
}
public int getJ() {
return j;
}
public void setJ(int j) {
this.j = j;
}
}
已经完成了
public class Array_i_max { int i; int i_end; int j_end; int j; Integer sum=0; public int getI() { return i; } public void setI(int i) { this.i = i; } public int getJ() { return j; } public void setJ(int j) { this.j = j; } }
这里我觉i_end和i我没用到,但是要是需要具体位置的话,可以改代码把i与i_end使用上。
对应每行最大子数组,找出包含此最大子数组的扩展的最大和矩阵。
Integer max_int_Array_Max(ArrayList<Integer> b,Array_i_max c) { Integer max=c.sum; Integer sum=c.sum; final int Line_Number=b.get(0); final int Column_Number=b.get(1); for(int m=1;m<Line_Number;m++) { for(int n=m*Line_Number+c.j;n<=m*Line_Number+c.j_end;n++) { sum=sum+b.get(n); } if(sum>max) { max=sum; } } return max; }
主要的函数:从包含此最大子数组的扩展的最大和矩阵中找出最大和矩阵
1 Integer max_int_Array_(ArrayList<Integer> b) 2 { 3 Integer sum=0; 4 Integer max=0; 5 Integer sum1=0; 6 final int Line_Number=b.get(0); 7 final int Column_Number=b.get(1); 8 ArrayList<Array_i_max> list1 = new ArrayList<Array_i_max>(); 9 int i=2; 10 for(int j=0;j<Column_Number;j++) 11 { 12 Array_i_max l=new Array_i_max(); 13 l.i=j; 14 l.i_end=j; 15 max=b.get(i); 16 l.j=i; 17 for(i=2;i<Line_Number+2;i++) 18 { 19 sum=sum+b.get(i); 20 if(sum<0) 21 { 22 sum=0; 23 l.j=i+1; 24 } 25 if(sum>max) 26 { 27 max=sum; 28 l.j_end=i; 29 l.sum=max; 30 } 31 } 32 33 list1.add(l); 34 } 35 for( i=0;i<list1.size();i++) 36 { 37 sum1=max_int_Array_Max(b,list1.get(i)); 38 if(max<sum1) 39 { 40 max=sum1; 41 } 42 } 43 return max; 44 }
文件操作和上面的一样,就是第一个数据为行,第二个数据为列,然后第三个数据才是矩阵数据本身。
操作结果:
public class MaxSumofMatrix { public static void main(String[] args) { //最大子矩阵的累加和 int matrix[][]={{-1,-1,-1},{-1,2,2},{-81,-7,-1}}; maxSum(matrix); } public static void maxSum(int matrix[][]) { if(matrix==null||matrix.length==0) return; int max=0; int col=matrix[0].length,row=matrix.length; for(int i=0;i<row;i++) { int arr[]=new int[col]; for(int j=i;j<row;j++) { //遍历所有的子行 for(int k=0;k<col;k++) { arr[k]+=matrix[j][k]; //将每子行的值进行相加然后利用子数组的最大和就可以求出子矩阵的最大和 } max=Math.max(maxSum(arr), max); //求出数组的子数组和最大值 } } System.out.println(max); } public static int maxSum(int arr[]) { int max=0,sum=0; for(int i=0;i<arr.length;i++) { if(sum<=0) { sum=arr[i]; } else { sum+=arr[i]; } max=Math.max(sum, max); } return max; } } --------------------- 作者:HankingHu 来源:CSDN 原文:https://blog.csdn.net/u013309870/article/details/70145481 版权声明:本文为博主原创文章,转载请附上博文链接!
总结:
没有总结,我现在脑子疼,不知道该总结啥。溜了,打游戏去了。
花费时间上课时间加昨晚七点到十点,今天八点到十一点左右,大多时间花费在思考。
代码量:算我删来删去的错误有个五六百行吧。代码不太规范,但很简单。
上面的代码只弄了函数,所有代码在下方:
一维数组的:
1 package 三月九号; 2 3 import java.io.BufferedReader; 4 import java.io.FileReader; 5 import java.io.IOException; 6 import java.util.ArrayList; 7 import java.util.Scanner; 8 9 public class TXT_duqu { 10 11 public static void main(String[] args) { 12 // TODO 自动生成的方法存根 13 String b="E:\\\\大二\\\\软件工程\\\\java\\\\src\\\\三月九号\\\\input.txt"; 14 ArrayList<String> list = new ArrayList<String>(); 15 list=wenjian(b); 16 ArrayList<Integer> list1 = new ArrayList<Integer>(); 17 list1=String_To_Integer( list); 18 for(int i=0;i<list1.size();i++) 19 { 20 System.out.println(list1.get(i)); 21 } 22 System.out.println(max_int_Array(list1)); 23 24 } 25 static Integer max_int_Array(ArrayList<Integer> b) 26 { 27 Integer sum=0; 28 Integer max=0; 29 for(int i=0;i<b.size();i++) 30 { 31 sum=sum+b.get(i); 32 if(sum<0) 33 { 34 sum=0; 35 } 36 if(sum>max) 37 { 38 max=sum; 39 } 40 } 41 if(sum==0) 42 { 43 max=b.get(0); 44 for(int i=1;i<b.size();i++) 45 { 46 if(max<b.get(i)) 47 { 48 max=b.get(i); 49 } 50 } 51 } 52 return max; 53 54 } 55 public static ArrayList<Integer> String_To_Integer(ArrayList<String> list) 56 { 57 ArrayList<Integer> list1 = new ArrayList<Integer>(); 58 for(int i=0;i<list.size();i++) 59 { 60 Integer integer =new Integer(list.get(i)); 61 list1.add(integer); 62 } 63 return list1; 64 65 } 66 public static ArrayList<String> wenjian(String b) 67 { 68 ArrayList<String> list = new ArrayList<String>(); 69 boolean flag=true; 70 try // 建立一个对象,它把文件内容转成计算机能读懂的语言 71 { 72 Scanner shuru = new Scanner(new BufferedReader(new FileReader(b))); 73 String a; 74 //网友推荐更加简洁的写法 75 while ((shuru.hasNext()) ) { 76 // 一次读入一行数据 77 a=shuru.next(); 78 if(isNumeric00(a)) 79 { 80 list.add(a); 81 } 82 else 83以上是关于题目:返回一个整数数组中最大子数组的和。的主要内容,如果未能解决你的问题,请参考以下文章