软件工程(2018)第三次作业

最大子段和

令f[i]为从莫一点开始到a[i]为止最大的子段和,则有以下转移方程:

\[f_i = \max(f_{i-1} + a[i], a[i])\]

因为只需遍历一次数组就可求出,所以复杂度为\(O(n)\)

package org.sequix.homework3;

/**
 * 提供求最大子段和的工具类。
 *
 * @author sequix
 * @version 0.0.1
 * @since 2018/03/26
 */
public class MaxSubArray {

    /**
     * 返回数组的最大子段和。
     * f[i] 到a[i]为止最大的子段和。
     * f[i] = max(f[i-1]+a[i], a[i])
     *
     * @param arr 被求数组
     * @return 最大子段和
     */
    public static int msa(int[] arr) {
        if (arr.length == 0) {
            throw new IllegalArgumentException("expected a non-empty array");
        }

        int cur = arr[0];
        int ans = cur;

        for (int i = 1, len = arr.length; i < len; ++i) {
            cur += arr[i];
            if (arr[i] > cur) cur = arr[i];
            if (cur > ans) ans = cur;
        }
        return ans;
    }
}

测试

为了方便的测试,这里另写了一个工具类TestUtils。

在TestUtils.msa中,以另一种方式求最大子段和。其枚举所有的子段,选出最大的。此解法时间复杂度为\(O(n^2)\),但其正确性显而易见,所以用于对拍测试。

package org.sequix.homework3;

import java.util.Random;

/**
 * 提供测试用工具函数。
 * @author squix
 * @since 2018/03/19
 */
class TestUtils {
    private static Random random = new Random(); 

    /**
     * 生成[min, max]范围内的随机数。
     * @param min 最小值,最小可为Integer.MIN_VALUE
     * @param max 最大值,最大可为Integer.MAX_VALUE
     * @return 生成的随机数
     */
    static int randomInteger(int min, int max) {
        long num = (long) max - min + 1;
        long kth = (long) (random.nextDouble() * num);
        long ret = (long) min + kth;
        return (int) ret;
    }

    /**
     * 生成随机数数组。
     * @param size 数组大小
     * @param minElement 元素最小值
     * @param maxElement 元素最大值
     * @return 生成的数组
     */
    static int[] generateRandomArray(int size, int minElement, int maxElement) {
        int[] arr = new int[size];
        for (int i = 0; i < size; ++i)
            arr[i] = TestUtils.randomInteger(minElement, maxElement);
        return arr;
    }

    /**
     * 返回数组的最大子段和。用于和MaxSubArry.msa()对拍。
     * @param arr 被求数组
     * @return 最大子段和
     */
    static int msa(int[] arr) {
        int length = arr.length;
        int[] sum = new int[arr.length];

        sum[0] = arr[0];
        for (int i = 1; i < length; ++i) {
            sum[i] = sum[i-1] + arr[i];
        }

        int ans = arr[0];
        for (int left = 0; left < length; ++left) {
            for (int right = left; right < length; ++right) {
                int tmp = sum[right];
                if (left > 0) tmp -= sum[left-1];
                if (ans < tmp) ans = tmp;
            }
        }
        return ans;
    }
}

具体的测试类如下:

package org.sequix.homework3;

import static org.junit.Assert.assertEquals;

import org.junit.Test;
import org.junit.jupiter.api.RepeatedTest;
import org.junit.platform.runner.JUnitPlatform;
import org.junit.runner.RunWith;

/**
 * MaxSubArray 的测试类。
 *
 * @author sequix
 * @version 0.0.1
 * @since 2018/03/26
 */
@RunWith(JUnitPlatform.class)
public class MaxSubArrayTest {
    @Test(expected=IllegalArgumentException.class)
    public void testEmptyArray() {
        int[] original = new int[0];
        MaxSubArray.msa(original);
    }

    @Test
    public void testGeneral() {
        int[] original = new int[] {-2, 11, -4, 13, -5, -2};
        int expected = TestUtils.msa(original);
        assertEquals(expected, MaxSubArray.msa(original));
    }

    @Test
    public void testOnlyNegatives() {
        int[] original = TestUtils.generateRandomArray(10000, -10000, -1);
        int expected = TestUtils.msa(original);
        assertEquals(expected, MaxSubArray.msa(original));
    }

    @Test
    public void testOnlyPositives() {
        int[] original = TestUtils.generateRandomArray(10000, 1, 10000);
        int expected = TestUtils.msa(original);
        assertEquals(expected, MaxSubArray.msa(original));
    }

    @RepeatedTest(10)
    public void testRandom() {
        int[] original = TestUtils.generateRandomArray(10000, -10000, 10000);
        int expected = TestUtils.msa(original);
        assertEquals(expected, MaxSubArray.msa(original));
    }
}

测试效果

外链

代码:Github

原文地址:https://www.cnblogs.com/sequix/p/8650477.html

时间: 2024-10-10 09:22:39

软件工程(2018)第三次作业的相关文章

软件工程(第三次作业)

软件工程(第三次作业) 组员:周德莉.王铭霞 一.题目 在之前编写的四则运算程序基础之上做如下改进: 1  请参照教材Page57:4.2-4.3节中内容,修改原程序,使之符合 “代码风格和设计规范”的基本要求: 2  请采用模块化设计思想,修改之前的code,将 “计算功能” 封装起来 小提示: 假如在C语言环境下,可将函数声明与具体实现分别存放在头文件(.h)和源文件(.c)中: 3  通过测试程序和API 接口,测试其简单的加法功能. 小提示: 单元测试方法请参看教材Page21:2.1.

软件工程课程前三次作业总结

不知不觉间,软件工程的课程已经过半,而且团队项目也已经进入了冲刺阶段,距离最后25号的项目完成期限越来越近了,我们每个团队的每个成员都需要继续努力,争取在期末检查的时候能够给冯老师以及各位辛勤的助教老师们一份完美的答卷. 在上个月的月底4月28日下午上课时,信息系和冯老师非常荣幸的邀请到了我们课本的作者邹欣老师以及各位助教老师,并邀请各位老师现场为各位同学的初期团队项目作点评分析,为每个团队的编程方向指出了一条明路,让各个团队都有信心沿着这条大路走向期末团队作业最终的成功!在这场精彩的点评之前,

软件工程(2018)结对编程第一次作业

第一次结对编程作业 代码审查表 功能模块名称 表达式的括号匹配 审查人 常远 审查日期 2018.4.4 代码名称 表达式的括号匹配 代码作者 郭靖 文件结构 重要性       审查项 结论                  头文件和定义文件的名称是否合理? 是 头文件和定义文件的目录结构是否合理? 是 版权和版本声明是否完整? 否 重要 头文件是否使用了 ifndef/define/endif 预处理块? 是 头文件中是否只存放"声明"而不存放"定义" 是 程序

《软件工程》 第三周 作业(一)

问题1:这个程序要找的是符合什么条件的数? 我认为这个程序要找的是一个范围从1到2^63-1的数,然后找出一个数不能被数组rg[]中两个相邻的数整除并且只能连续的两个数不可以被整除,剩下的数可以被整除 . 问题2:这样的数存在么?符合这一条件的最小的数是什么? 好像是1+2+2^2+2^3+......+2^((63-1)/2)=(2^32)-1/(2-1)=2147483647,感觉似乎做错了,但是实在不太会做. 问题3:在电脑上运行这一程序,你估计多长时间才能输出第一个结果?时间精确到分钟(

解题报告——-2018级2016第二学期第三周作业

解题报告——2018级2016第二学期第三周作业 A:[NOIP2002P]过河卒 题目: 描述 如图,A 点有一个过河卒,需要走到目标 B   点.卒行走规则:可以向下.或者向右.同时在棋盘上的任一点有一个对方的马(如上图的C点),该马所在的点和所有跳跃一步可达的点称为对方马的控制点.例 如上图 C  点上的马可以控制 9 个点(图中的P1,P2 … P8 和 C).卒不能通过对方马的控制点. 棋盘用坐标表示,A 点(0,0).B 点(n,m)(n,m 为不超过 20  的整数,并由键盘输入)

2018上第三次作业

要求一:完成PTA作业 答:作业已完成! 要求二:pta作业编程题目的解题思路和调试过程记录 C高级第三次作业(1) 完成情况如图: 第一题:输出月份英文名 1.设计思路: (1)算法: 第一步:定义一个指针数组,数组内容为各个月份,再定义一个整形变量s: 第二步:如果n的值在1~12之间,那么就返回s: 第三步:如果n值不在1~12,那么就把NULL赋值给s,再返回s. (2)流程图: 主函数 调用函数 2.实验代码: char *getmonth( int n ){ int s; char

马哥2016全新Linux+Python高端运维班第三周作业作答

                    马哥2016全新Linux+Python高端运维班第三周作业                                           1.列出当前系统上所有已经登录的用户的用户名,注意:同一个用户登录多次,则只显示一次即可.     [[email protected] ~]# who | awk '{print $1 $NF}'| uniq -d     [[email protected] ~]# who     yicx     :0  

第三次作业问卷

看到一个问卷不错,拟作为第三次作业的部分内容. 你对自己的未来有什么规划?做了哪些准备? 答:未来走一步算一步,计划赶不上变化,充实自己的知识,多增加一点自己经验,比起知识,更重要的是社交. 你认为什么是学习?学习有什么用?现在学习动力如何?为什么? 答:学习,就是知道一些以前不知道的事.厉害的人有两点:观察力和文化底蕴,学习就是为了增加知识储备,尽量不出现书到用时方恨少的情况.目前的学习动力很缺乏,因为一到大学开始想着混. 你感觉自己什么事情做的比较成功?有什么经验? 答:并不知道,似乎没有什

魏昊卿——《Linux内核分析》第三周作业:Linux系统启动过程

魏昊卿——<Linux内核分析>第三周作业:Linux系统启动过程 一.实验部分 实验指导 使用实验楼的虚拟机打开shell 1 cd LinuxKernel/ 2 qemu -kernel linux-3.18.6/arch/x86/boot/bzImage -initrd rootfs.img 内核启动完成后进入menu程序(<软件工程C编码实践篇>的课程项目),支持三个命令help.version和quit,您也可以添加更多的命令,对选修过<软件工程C编码实践篇>

职业规划第三次作业

看到一个问卷不错,拟作为第三次作业的部分内容. 你对自己的未来有什么规划?做了哪些准备? 答: 学好大学四年的课程,并积极参加各种活动来锻炼自己的能力.在实习期间认真学习工作经验,学习经验然后争取能自己创业 好好交友,多读书, 你认为什么是学习?学习有什么用?现在学习动力如何?为什么? 答:学习是通过他人的言传身教了解知识,将他人的认识转化为自己的知识.学习能够取他人之长补己之短,丰富自己的认知,还避免了闭门造车和坐井观天的错误.现在的学习动力一般,因为新学知识对我来说比较陌生. 你感觉自己什么