题目:
随机出一个一维数组,设该数组为循环数组,求其最大小子数组。
一、设计思路
求最大子数组,就求出最大的连续正子数组。
将数组分为全负和有非负值两种情况。全负求出最大值即可。
在有非负值的情况下,先判断该随机数组的首尾是否相连,即首尾是否都大于等于零。如果首尾相连,则将该一维数组分为首、中、尾三部分,先求出首尾和S1,再求中间最大连续正子数组和S,令S1和S与maxS相比较,求出最大子数组;如果首尾不相连,则直接借鉴前一种情况中部的算法,求最大正子数组S。
二、源代码
1 //刘双渤,刘洪阳,循环一维数组求最小子数组 2 package zishuzu; 3 import java.util.*; 4 5 public class zuidazishuju { 6 7 /** 8 * @param args 9 */ 10 public static void main(String[] args) { 11 // TODO Auto-generated method stub 12 13 Scanner sc = new Scanner(System.in); 14 15 int n,max,min; 16 int i; 17 System.out.println("请输入一维数组的长度:"); 18 n = sc.nextInt(); 19 System.out.println("请输入该数组元素的取值范围(请保证前一个值小于后一个值):"); 20 min = sc.nextInt(); 21 max = sc.nextInt(); 22 23 int[] a = new int[n]; 24 25 for(i = 0;i < n;i++) 26 { 27 a[i] = min + (int)(Math.random()*(max-min)); 28 } 29 30 System.out.println("该一维循环随机数组为:"); 31 for(i = 0;i < n;i++) 32 { 33 System.out.print(a[i] + " "); 34 } 35 System.out.println(); 36 37 int maxS,shouS1 = 0,weiS1 = 0,shouS = 0,weiS = 0,S,S1; 38 int js,midSta = 0,midSta1 = 0,loci; 39 int[] loc = new int[n]; 40 int judge = 0; 41 42 for(i = 0;i < n;i++) //判断数组元素是否含有非负数 43 { 44 if(a[i] >= 0) 45 { 46 judge = 1; 47 midSta1 = i; 48 break; 49 } 50 } 51 maxS = a[0]; 52 S = 0; 53 S1 = 0; 54 js = 0; 55 loci = 0; 56 if(judge == 0) //所有元素小于零 57 { 58 for(i = 0;i < n;i++) 59 { 60 if(a[i] > maxS) 61 { 62 maxS = a[i]; 63 loci = 0; 64 loc[loci] = i+1; 65 } 66 else if(a[i] == maxS) 67 { 68 loci += 1; 69 loc[loci] = i +1; 70 } 71 } 72 System.out.println("最大子数组和为:" + maxS); 73 System.out.println("数组第一个元素位置为"1""); 74 System.out.print("最大子数组所在位置为:"); 75 for(i = 0;i <= loci;i++) 76 { 77 System.out.print(loc[i] + " "); 78 } 79 } 80 else //正负同时存在 81 { 82 if(a[0] >= 0 && a[n - 1] >= 0) //第一个元素和最后一个元素非负 83 { 84 for(i = 0;i < n;i++) //从0开始求第一个连续非负子数组 85 { 86 if(a[i] >= 0) 87 { 88 S1 += a[i]; 89 weiS1 = i + 1; 90 if(i == n -1) 91 { 92 shouS1 = 1; 93 } 94 } 95 else 96 { 97 break; 98 } 99 } 100 for(i = n - 1;i > weiS1;i--) //从n-1开始求连续非负子数组 101 { 102 if(a[i] >= 0) 103 { 104 S1 += a[i]; 105 shouS1 = i +1; 106 } 107 else 108 { 109 break; 110 } 111 } 112 if(S1 >= maxS) //首尾相连子数组与maxS比较 113 { 114 maxS = S1; 115 shouS = shouS1; 116 weiS = weiS1; 117 } 118 for(i = weiS1;i < shouS1 - 1;i++) //求中间第一个非负数 119 { 120 if(a[i] >= 0) 121 { 122 midSta = i; 123 break; 124 } 125 else if(i == shouS1 - 2) 126 { 127 midSta = i + 1; 128 } 129 } 130 for(i = midSta;i < shouS1 - 1;i++) //求中间最大连续非负子数组 131 { 132 if(a[i] >= 0) 133 { 134 S += a[i]; 135 js++; 136 } 137 else 138 { 139 if(S >= maxS) 140 { 141 maxS = S; 142 weiS = i -1; 143 shouS = i -js; 144 js = 0; 145 S = 0; 146 } 147 else 148 { 149 S = 0; 150 js = 0; 151 } 152 } 153 } 154 } 155 else //首尾不是连续非负子数组的情况 156 { 157 for(i = midSta1;i < n;i++) //求最大连续非负子数组 158 { 159 if(a[i] >= 0) 160 { 161 S += a[i]; 162 js++; 163 } 164 else 165 { 166 if(S >= maxS) 167 { 168 maxS = S; 169 weiS = i ; 170 shouS = i -js + 1; 171 js = 0; 172 S = 0; 173 } 174 else 175 { 176 S = 0; 177 js = 0; 178 } 179 } 180 } 181 } 182 System.out.println("最大子数组和为:" + maxS); 183 System.out.println("数组第一个元素位置为"1""); 184 System.out.println("最大子数组首位置为:" + shouS); 185 System.out.println("最大子数组尾位置为:" + weiS); 186 } 187 sc.close(); 188 } 189 190 }
三、设计过程
先给出随机一维子数组,然后分情况完成。
全负情况比较简单,但考虑到有相同最大值存在的情况,于是建立一个一维数组loc[n]来保存相同最大值的位置。验证时,发现多最大值的情况下总是为在输出的位置的最前边多一个,修改初始值解决。
有非负值情况下,在计算首尾和S1时,如果数组全正,则有可能S1为实际值的两倍,因此根据weiS1来判断首尾位置,避免重复相加。在设计中间部分是,如何跳过负值和保存判断最大子数组和是关键,一开始的想法是在出现第一个非负值的情况下保存判断最大子数组和,并将S,js初始化为0,逻辑上不知没有找出错误,最后使用的方法是在每一个负值出现时就判断保存和初始化,成功。
四、实验结果:
有非负值存在且首尾相连:
有非负值且首尾不想连:
全正:
全负:
五、结组成员
刘双渤,刘洪阳。
共同完成设计思路。