最大子序列和——简单问题的不简单之处

题目:

给定一整型数列{a1,a2...,an},找出连续非空子串{ax,ax+1,...,ay},使得该子序列的和最大,其中,1<=x<=y<=n。

最终代码:

 1 import java.util.*;
 2 import java.math.*;
 3 public class Main {
 4
 5     public static void main(String[] args) {
 6         Solution s = new Solution();
 7         Scanner sc = new Scanner(System.in);
 8         int N = sc.nextInt();
 9         int[] result = new int[N];
10         for(int i = 0; i < N; i++) {
11             int length = sc.nextInt();
12             int[] array = new int[length];
13             for(int j = 0; j < length; j++) {
14                 array[j] = sc.nextInt();
15             }
16             result[i] = s.getResult(array, length);
17         }
18         sc.close();
19         for(int i : result) {
20             System.out.println(i);
21         }
22     }
23
24 }
25 class Solution {
26     public int getResult(int[] array, int length) {
27         int max = array[0];
28
29         for(int i : array) {
30             max = max >= i ? max : i;
31         }
32         if(max < 0)
33             return max;
34         else
35             max = 0;
36
37         int sum = 0;
38         for(int i = 0; i < length; i++) {
39             sum += array[i];
40             max = sum > max ? sum : max;
41             if(sum <= 0)
42                 sum = 0;
43         }
44         return max;
45     }
46 }

首先,这确实不是一道很难的题目。相信很多人第一次看见都在《数据结构和算法分析》这本书里面。

当然,题目似乎在不同的地方有点不同,比如某个网站上的这道题说如果输入都是负数就输出0(这实质上倒是简化了程序,但不是重点)。

我主要想通过这篇博客记录的是一种动态规划的思想过程。我是在动态规划问题里面找到这个问题的,并且一时间没有想起来这道问题的那个最优解,便开始用动态规划的思想解决这道题目,反而出现了不小的问题。到现在,我依然只是在理解动态规划的路上,所以文章必然有错误。谬误之处,望请海涵。

众所周知的是动态规划最困难的点是在明确一个具体问题的状态,和状态转移方程。这道题目我一开始一直认为状态以下两者之一:

1,以当前数字结尾的序列的最大和

2,是在当前数字之前的序列的最大和。

这里所谓的当前数字是指,比如用一个i循环这个数组,i循环到的地方。代码需要根据之前的状态和Array[i]的大小来确定决策。而当i循环到输入序列的末尾,自然求出来的就是问题要求的这个序列的最大子序列和。

然而我还没开始编写程序就感觉十分怪异,因为如果按照以上两种状态的设置方式都无法想到有一个明确而高效的状态转移方程来求出最优解。(事实上动态规划的问题如果自己都没有想通整个过程做出来很大几率是错的)

然后我查了下,想起了这道题的出处,用记忆中的算法很快解决了这一个问题,

那么重点来了,我一开始的思路哪里错了呢?通过最佳做法倒过来分析,我一开始的想法基于:状态就是目前这个数字i之前或以之结尾的的最大子序列和。(可是事实上都有很多问题)。

最后看来:

1,状态是:从某个起始节点j到当前i的序列和。

2,决策是:确定起始节点j的位置。

3,状态转移方程是:如果当前序列的序列和小于0了,就“断开”,从i + 1重新开始,否则当前序列直接加上Array[i]这个数字。

4,阶段是:没有遇到“断点”的一个序列。

断开是指:如果当前的序列和小于0,可以认定它是一个“累赘”,也就是说,把它连接到后面的序列所产生的新的序列和的值,不可能比后面的序列自己的序列和还大,因为这是一个负数。

这么做的话,即使在i的遍历中遇到负数,也无需多虑,因为max只保持最大值。而“断开”的做法,能保证j,i(j <= i)只会在需要考察的点出现,不会去在不可能出现max的地方寻找。

这道题真不是难题,可是分析一下可以得到很多。我用动态规划已开始没有分析出来,原因是我先入为主地认为状态一定和所求的东西有关,所以我先认定的状态都是max,而不是sum。而实际上这道题的一个点就在所求的东西和需要的状态不一致,也不是简单的到了最后比较一下大小就可以得到的。是在用状态约束范围,在一定范围里面用一个Max来进行比较。

算是我学习动态规划路上的一点思考吧,肯定还有不完善的地方,我以后再补上。

时间: 2024-10-14 11:01:53

最大子序列和——简单问题的不简单之处的相关文章

Java设计模式(一) 简单工厂模式不简单

原创文章,转载请务必将下面这段话置于文章开头处. 本文转发自Jason's Blog,原文链接 http://www.jasongj.com/design_pattern/simple_factory 简单工厂模式使用案例 有一种抽象产品--汽车(Car),同时有多种具体的子类产品,如BenzCar,BMWCar,LandRoverCar.类图如下 作为司机,如果要开其中一种车,比如BenzCar,最直接的做法是直接创建BenzCar的实例,并执行其drive方法,如下 package com.

修正《更简单的 编辑器从光标处插入图片(失去焦点后仍然可以在原位置插入)》中的一个问题

转载请注明: TheViper http://www.cnblogs.com/TheViper  以前写过一篇更简单的 编辑器从光标处插入图片(失去焦点后仍然可以在原位置插入),里面只测试了ie,事实上在firefox中有个小问题,就是不管插入图片前,编辑器有没有焦点(光标),在插入后,光标会消失. 插入前没有焦点 插入前有焦点 修正 function insertImage(html){ restoreSelection(); if(document.selection) currentRan

一个简单代码的不简单实现

前几天看有人贴了一个java代码的问题,实在有意思,今天拿出来和大家分享分享.题目是这样的:给定两个Integer类型的变量a和b,要求实现一个函数swap,交换他们的值.代码如下: ====想一想的分割线 ==== 大家用30秒钟想想怎么样实现呢? ====时间到的分割线 ==== 估摸着好多盆友一看这个题目,第一反应是:擦,这么简单的题,让我来做,是不是在侮辱我的智商!!! 最简单的实现: 这题目初看一眼,确实好简单,可能只需要10秒钟就可以完成(主要时间花在打字上): 好了,这就是实现代码

line-height与vertical-align:简单的属性不简单

学习过CSS肯定对line-height与vertical-align两个属性有印象:line-height用来设置行高,vertical-align用来设置文本垂直方向的对齐方式,两种看似十分简单,但是其应用及原理却不简单 line-height line-height与内容 先思考个问题:默认的div元素高度为0,为什么添加了文字之后,高度就有了?这个高度是由哪个属性决定的?如果是span元素,高度又是又谁决定的呢? 如上图所示,结果应该很明确了:影响div元素高度的是line-height

简单的线条不简单的画

简单的线条,不简单的画,网友:画的太有意境了 画是有意境的 ,怎么才能用最简单的线条,画出最有意境的画,这是很有难度的,但是只要你掌握好基本构图法,加上适当的艺术美感,就能画出来,网友:太有意境了. 初学者在临摹的过程中,一定要领悟体会这些画,每一幅画都是有自己的独特的构图法加上艺术美感的处理,最终才用简单的线条,画出了不简单的画. 原文地址:https://www.cnblogs.com/bzluohai/p/12698718.html

简单背后的不简单&mdash;&mdash;初识arduino(stm32)

每一篇博文都是本人原创,禁止转载 知道arduino是在上大学的时候,但是在很多做单片机 开发的人眼中看来,arduino是给外行人玩的,因此自诩为专业嵌入式开发的很多人(当然也包括我)对这种东西当然是不屑的.因为机缘巧合,我有了一种想要学习arduino软件构架的想法,因为最早的arduino的是基于avr单片机,我手头没有相关的硬件,因此我打算使用目前广泛使用的stm32的单片机开始对arduino的背后代码的研究. 最早开发arduino对stm32支持的是LeafsLabs公司( htt

C#简单问题,不简单的原理:不能局部定义自定义类型(不含匿名类型)

今天在进行代码测试时发现,尝试在一个方法中定义一个委托,注意是定义一个委托,而不是声明一个委托变量,在编写的时候没有报错,VS也能智能提示,但在编译时却报语法不完整,缺少方括号,但实际查询并没有缺少,想不通原因,将委托定义移到类中,报错消失,编译成功了. 先看一下报错的源码:(实际上不只委托类型,所有的自定义类型均报错) class Class2 { public void Test() { delegate void testDel(string p); //是错误的 event testDe

看似简单,却不简单的前端那些事

基础篇 1.文档流/网页流(正确理解为普通流) 稳定性:标准流〉浮动流〉 定位流 (优先用标准流). 2.网页宽度 pc:一般是950-1200px(具体问题具体分析,看需求来定,不同类型网站,会有不同宽度). mobile:一般以苹果手机iphone5(640x1136px)为基准.(暂不考虑平板电脑,以苹果移动端的尺寸来兼容android移动端的尺寸,难怪那么多人买iphone手机,网页体验最好.) PS:响应式网站随意,不固定. 3.相对路径与绝对路径 使用相对路径的 "."--

更简单的 iframe从光标处插入图片(失去焦点后仍然可以在原位置插入)

转载请注明: TheViper http://www.cnblogs.com/TheViper 前天晚上发现上一篇iframe从光标处插入图片(失去焦点后仍然可以在原位置插入里面的用法在ie6,7中无效,好悲催,当初只测试了ie8就以为在ie6,7上也没问题. 昨天在github上发现了一个很好的富文本编辑器wangEditor,一看名字就是中国人写的.这个编辑器好在支持ie6+,另外最重要的一点,它在ie6,7,8上都可以做到失去焦点后仍然可以在原位置插入图片,而且代码量很少.于是很好奇的看看