关于求已知整数数组的连续子数组的最大和的方法 ——基于一维数组的循环,甚至推广到二维情况上
日期:2019.3.21
博客期:049
星期四
先二话不说,先交代码,今天训练的内容是“这个整数数组是允许开头和结尾结合在一起的”,大家的思路都是扩大数组内容,就是将读入的数据存入数组,并将数据量扩大一倍——把开头和结尾相连!
我仔细一想这也可以啊!但是当老师讨论到数组位数的时候,他说最多设置位数不超过 2N-1 (N是原数组的位数),这里我想如果取全部的数据该怎么办?
实例: 1,2,-3,2,0
按照以前的算法应该取得 1,2 ,得到结果 3
按照新算法得到 2,0,1,2 ,得到结果 5
但是大家说的算法是连接数组,也就是得到新数组 1,2,-3,2,0,1,2,-3,2 ;从而算得结果为 5 ,但是如果全部是正数呢?应该加以判断?
实例2:10, -20, 25, -50 ,15
得到结果应该是取得 15,10,-20,25 ,得到结果30
下边详细介绍一下我的方法:
添加前边最大值的记录和前边最小值的记录,其中这个最小值一定是的位数一定要大于取得最大值时的记录,最终计算比 rmax 大的内容—— 总值 - 最小值 + 最大值(得到的这个记录是连同最后一个值和第一个值的最大和)
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 package pvp; 2 3 import java.io.File; 4 import java.io.FileNotFoundException; 5 import java.util.Scanner; 6 7 public class TestPlay4 { 8 public static void main(String[] args) { 9 //AddRandomNumber.Renew3(); 10 File f = new File("data/data.txt"); 11 if(!f.exists()) 12 { 13 System.out.println("文件不存在!"); 14 System.exit(0); 15 } 16 //存储导入内容 17 String str; 18 //内容 19 Scanner sc = null; 20 try { 21 sc = new Scanner(f); 22 } catch (FileNotFoundException e1) { 23 System.out.println("文件不存在!"); 24 System.exit(0); 25 } 26 //最大值 27 int rmax = Integer.MIN_VALUE; 28 //正数总值 29 int Tnum = Integer.MIN_VALUE; 30 //负数总值 31 int Fnum = 0; 32 //记录是否发生转变 33 int sis = 0; 34 //标记是第几程度 35 int attitude = 0; 36 //------------------------<Test4新加内容> 37 //标记从第1个开始数的最大值 38 int isState = 0; 39 //标记从第1个开始数的最小值 40 int isNotState = 0; 41 //内容标记 42 int kort = 0; 43 //从第1个开始数的最大值的位置 44 int u_er = 0; 45 //从第1个开始数的最小值的位置 46 //int v_er = 0; 47 //------------------------</Test4新加内容> 48 //循环 49 try 50 { 51 //--------------------[Test4新加内容] 52 int p_num = 0;//------[Test4新加内容] 53 //--------------------[Test4新加内容] 54 if(!sc.hasNext()) 55 { 56 System.out.println("文件内容为空!"); 57 System.exit(0); 58 } 59 while(sc.hasNext()) 60 { 61 ++p_num; 62 int p; 63 str = sc.next(); 64 p = Integer.parseInt(str); 65 if(attitude==0) //---------------------------------------[寻找第一个正数] 66 { 67 if(p<=0) 68 ; 69 else 70 { 71 Tnum = p; 72 attitude = 1; 73 } 74 } 75 else if(attitude==1) //---------------------------------------[上一个数为正数] 76 { 77 if(p<0) 78 { 79 if(sis==0) 80 { 81 sis = 1; 82 Fnum += p; 83 } 84 else 85 Fnum = p; 86 attitude = -1; 87 } 88 else 89 Tnum += p; 90 91 if(Tnum>rmax) 92 rmax = Tnum; 93 } 94 else //---------------------------------------[上一个数为负数] 95 { 96 if(p>0) 97 { 98 attitude = 1; 99 if(Tnum + Fnum > 0) 100 { 101 if(Tnum + Fnum > Integer.MAX_VALUE - p) 102 { 103 System.out.println("统计内容超过最大值!"); 104 System.exit(0); 105 } 106 Tnum = (Tnum + Fnum) + p; 107 } 108 else 109 Tnum = p; 110 } 111 else 112 { 113 if(Fnum<Integer.MIN_VALUE-p) 114 { 115 System.out.println("统计内容超过最小值!"); 116 System.exit(0); 117 } 118 Fnum += p; 119 } 120 } 121 if(p>rmax) 122 rmax = p; 123 if(Tnum>rmax) 124 rmax = Tnum; 125 126 kort = kort + p; 127 128 if(isState<kort) 129 { 130 isState = kort; 131 u_er = p_num; 132 } 133 if(isNotState>kort&&p_num>=u_er) 134 isNotState = kort; 135 else if(p_num<u_er) 136 isNotState = 0; 137 } 138 //--------------------[Test4新加内容] 139 if(kort-isNotState+isState>rmax) 140 rmax = kort-isNotState+isState; 141 //--------------------[Test4新加内容] 142 } 143 catch( NumberFormatException e){ 144 System.out.println("输入内容不是数字或者过大!"); 145 System.exit(0); 146 } 147 System.out.println(rmax); 148 sc.close(); 149 } 150 }
Part 2:那么,下面就让我们进入第二阶段吧!那就是二维数组阶段!
简而言之,就是如图得到和最大的分块!还必须是矩形!
呃~想着说一下思路,说一下我是如何从一维数组到二维数组进行转换的:
1、一维数组
计算每一个位置的数组和,利用公式得到每一项的结果,通过最大值减去最小值,最大值位数大于最小值得到部分连续和!
2、二维数组
计算每一个位置的数组和,利用公式得到每一项的结果,通过诱导得到的余角(如图中的3,2,-9,-1,-2,0,2)的和最小值 min,之后用当前的总值减去min得到的值的最大值就是所求的最大值了!
得到了和数组,如何得到第 k 行,第 l 列的数据到第 i 行,第 j 列的数据和:
从而根据思路,诱导引出结果:
图上是到 i = 6, j = 4时,k = 1, l = 3时得到的结果。
上图中分别有以下含义:
黄色背景区域区域表示 i 和 j 所覆盖的区域。
蓝色字迹所取到的区域是 确认是否为最大值的连续子数组区域。
红色字迹的区域是黄色背景区域 减去 蓝色字迹区域。
我的思想就是通过 i 和 j 的每一次的遍历中,通过红色字迹区域的取得的最小值,和黄色背景区域的固定值做差,找到在蓝色字迹区域的最大值。然后再统计找出每一个 i 和 j 的组合过程中取到的最大值的集合里面的最大值,那就是我们要寻找的结果了!
实现的初步代码如下:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 package pvp; 2 3 import java.io.File; 4 import java.io.FileNotFoundException; 5 import java.util.Scanner; 6 7 public class TestPlay5 { 8 public static void main(String[] args) { 9 //AddRandomNumber.Renew(); 10 File f = new File("data/data2.txt"); 11 if(!f.exists()) 12 { 13 System.out.println("文件不存在!"); 14 System.exit(0); 15 } 16 //存储导入内容 17 String str; 18 //内容 19 Scanner sc = null; 20 try { 21 sc = new Scanner(f); 22 } catch (FileNotFoundException e1) { 23 System.out.println("文件不存在!"); 24 System.exit(0); 25 } 26 //最大值 27 int rmax = Integer.MIN_VALUE; 28 //和数组 29 int [][]q; 30 //循环 31 try 32 { 33 if(!sc.hasNext()) 34 { 35 System.out.println("文件内容为空!"); 36 System.exit(0); 37 } 38 int m,n; 39 m = sc.nextInt(); 40 q = new int [m][]; 41 if(!sc.hasNext()) 42 { 43 System.out.println("文件内容缺少!"); 44 System.exit(0); 45 } 46 n = sc.nextInt(); 47 for(int i=0;i<m;++i) 48 { 49 q[i] = new int [n]; 50 if(!sc.hasNext()) 51 { 52 System.out.println("文件内容缺少!"); 53 System.exit(0); 54 } 55 for(int j=0;j<n;++j) 56 { 57 int p; 58 str = sc.next(); 59 p = Integer.parseInt(str); 60 61 if(i==0) 62 { 63 if(j==0) 64 q[i][j] = p; 65 else 66 q[i][j] = q[i][j-1] + p; 67 } 68 else 69 { 70 if(j==0) 71 q[i][j] = q[i-1][j] + p; 72 else 73 q[i][j] = q[i][j-1] + q[i-1][j] - q[i-1][j-1] + p; 74 } 75 int temp = 0; 76 for(int k=0;k<i;++k) 77 { 78 for(int l=0;l<j;++l) 79 { 80 if(temp>=q[i][l]+q[k][j]-q[k][l]) 81 temp = q[i][l] + q[k][j] - q[k][l]; 82 } 83 } 84 if(rmax<q[i][j]-temp) 85 rmax = q[i][j] - temp; 86 } 87 } 88 } 89 catch( NumberFormatException e){ 90 System.out.println("输入内容不是数字或者过大!"); 91 System.exit(0); 92 } 93 System.out.println(rmax); 94 sc.close(); 95 } 96 }
我再次更新一下新的二维数组的代码,多加考虑了总值减去最小值的问题,请以下方代码为准
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 package pvp; 2 3 import java.io.File; 4 import java.io.FileNotFoundException; 5 import java.util.Scanner; 6 7 public class TestPlay6 { 8 public static void main(String[] args) { 9 //AddRandomNumber.Renew(); 10 File f = new File("data/data2.txt"); 11 if(!f.exists()) 12 { 13 System.out.println("文件不存在!"); 14 System.exit(0); 15 } 16 //存储导入内容 17 String str; 18 //内容 19 Scanner sc = null; 20 try { 21 sc = new Scanner(f); 22 } catch (FileNotFoundException e1) { 23 System.out.println("文件不存在!"); 24 System.exit(0); 25 } 26 //最大值 27 int rmax = Integer.MIN_VALUE; 28 //和数组 29 int [][]q; 30 //循环 31 try 32 { 33 if(!sc.hasNext()) 34 { 35 System.out.println("文件内容为空!"); 36 System.exit(0); 37 } 38 int m,n; 39 m = sc.nextInt(); 40 q = new int [m][]; 41 if(!sc.hasNext()) 42 { 43 System.out.println("文件内容缺少!"); 44 System.exit(0); 45 } 46 n = sc.nextInt(); 47 for(int i=0;i<m;++i) 48 { 49 q[i] = new int [n]; 50 if(!sc.hasNext()) 51 { 52 System.out.println("文件内容缺少!"); 53 System.exit(0); 54 } 55 for(int j=0;j<n;++j) 56 { 57 int p; 58 str = sc.next(); 59 p = Integer.parseInt(str); 60 61 if(i==0) 62 { 63 if(j==0) 64 q[i][j] = p; 65 else 66 q[i][j] = q[i][j-1] + p; 67 } 68 else 69 { 70 if(j==0) 71 q[i][j] = q[i-1][j] + p; 72 else 73 q[i][j] = q[i][j-1] + q[i-1][j] - q[i-1][j-1] + p; 74 } 75 int temp = 0; 76 for(int k=-1;k<i;++k) 77 { 78 for(int l=-1;l<j;++l) 79 { 80 if(k==-1) 81 { 82 if(l==-1) 83 { 84 continue; 85 } 86 else 87 { 88 if(temp>=q[i][l]) 89 temp = q[i][l]; 90 } 91 } 92 else 93 { 94 if(l==-1) 95 { 96 if(temp>=q[k][j]) 97 temp = q[k][j]; 98 } 99 else 100 { 101 if(temp>=q[i][l]+q[k][j]-q[k][l]) 102 temp = q[i][l] + q[k][j] - q[k][l]; 103 } 104 } 105 } 106 } 107 if(rmax<q[i][j]-temp) 108 rmax = q[i][j] - temp; 109 } 110 } 111 } 112 catch( NumberFormatException e){ 113 System.out.println("输入内容不是数字或者过大!"); 114 System.exit(0); 115 } 116 System.out.println(rmax); 117 sc.close(); 118 } 119 }