一.题目
问题: 给定n个整数(可能为负数)组成的序列a[1],a[2],a[3],…,a[n],求该序列如a[i]+a[i+1]+…+a[j]的子段和的最大值。当所给的整数均为负数时定义子段和为0,依此定义,所求的最优值为: Max{0,a[i]+a[i+1]+…+a[j]},1<=i<=j<=n 例如,当(a[1],a[2],a[3],a[4],a[5],a[6])=(-2,11,-4,13,-5,-2)时,最大子段和为20。
最大子段和是动态规划中的一种。(来自百度)
二.代码及算法思想
1.代码
首先看代码吧。解决这道题的代码如下:
代码地址:(https://github.com/xiepeiliang/homeworks/blob/master/Junit/app/src/main/java/com/example/xpl/junit/MaxSum.java)
public class MaxSum {
public int getMaxSum(int a[]) {
int len = a.length;
int partSum = a[0];
int maxSum = a[0];
for(int i = 1; i < len; i++) {
partSum = Math.max(a[i], partSum + a[i]);
maxSum = Math.max(maxSum, partSum);
}
if(maxSum < 0)
return 0;
else
return maxSum;
}
}
在上述代码中,起主要作用的代码就两行:
partSum = Math.max(a[i], partSum + a[i]);
maxSum = Math.max(maxSum, partSum);
2.解释
算法思想也凝聚在上面这两行代码里。此算法复杂度为0(n),只在每次循环里加一个数。
这里给大家讲一下我对这段代码的理解,其中两个变量,partSum和maxSum,partSum可理解为动态最大和,maxSum为实际最大和,当然在循环中,这两个变量的值的意义也是在0~i这个范围内的。举个例子,要求出数组a[] = {5, -2, 3}的最大字段和,首先使动态最大和partSum、实际最大和maxSum都等于5,然后,将a数组中的第二个元素-2与partSum+(-2)做比较,令partSum取其中大的数,也就是partSum = max(5+-2, -2) = 3,随后使上一个状态的实际最大值与此时的动态最大值做比较,并取其中大的数做新的实际最大值,也就是maxSum = max(5, 3) = 5,所以当遍历到a数组第二个元素时,实际最大和是5;然后遍历到a数组的第三个元素,重复上述的取partSum与maxSum的步骤,可以得到最后的maxSum = 6。
3.程序流程图
三.利用AndroidStudio中的Junit进行代码测试
1.设计条件组合覆盖用例
这里选择条件组合覆盖来对该代码设计测试用例。
关于各种覆盖标准的理解,这里推荐一篇博文(https://blog.csdn.net/virus2014/article/details/51217026)
对第二部分的流程图进行分析,将i >=len这个任何情况都会覆盖的分支屏蔽,只分析其分支。分析后得知,有四条路径ace、ade、bde、bdf程序存在执行。现在对这四条路径进行设计组合覆盖条件:
测试用例 | 期待值 | 覆盖条件 |
---|---|---|
{-2,11,-4,13,-5,-2} | 20 | bde |
{-5,-3,-2} | 0 | bdf |
{-5,3,2,4} | 9 | ace |
{1,2,3,-1} | 6 | ade |
由于对一个函数进行多数据测试,于是使用Junit参数化测试,测试代码如下:
代码地址:(https://github.com/xiepeiliang/homeworks/blob/master/Junit/app/src/test/java/com/example/xpl/junit/MaxSumTest.java)
package com.example.xpl.junit;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
import java.util.Arrays;
import java.util.Collection;
import static org.junit.Assert.*;
/**
* Created by xpl on 18-3-27.
*/
@RunWith(Parameterized.class)
public class MaxSumTest {
private int expected;
private int[] input;
public MaxSumTest(int expected, int[] input){
this.expected = expected;
this.input = input;
}
@Parameterized.Parameters
public static Collection words() {
return Arrays.asList(new Object[][]{
{20, new int[]{-2, 11, -4, 13, -5, -2}},
{0, new int[]{-5, -3, -2}},
{9, new int[]{-5, 3, 2, 4}},
{6, new int[]{1, 2, 3, -1}}
});
}
@Test
public void getMaxSum() throws Exception {
assertEquals(expected, new MaxSum().getMaxSum(input));
}
}
2.测试结果
测试结果如下图:
可以看到,四组测试数据均通过。
4.总结
通过此次作业,我对于Junit的测试有了更加充分的掌握,掌握了Junit的参数测试方法,同时也对覆盖标准有了更加深刻的理解。