K:求取数组中最大连续子序列和的四个算法
相关介绍:
求取数组中最大连续子序列和问题,是一个较为“古老”的一个问题。该问题的描述为,给定一个整型数组(当然浮点型也是可以的啦),求取其下标连续的子序列,且其和为该数组的所有子序列和中值为最大的。例如数组A={1, 3, -2, 4, -5},则最大连续子序列和为6,即1+3+(-2)+ 4 = 6。解决该问题的算法有四种,根据其时间复杂度的高低,下面分别为这四种算法做介绍。
第一种:时间复杂度为O(N^3)
该算法也是最容易想到的,很直观的算法,其算法的思路为,穷举数组中以某个元素为起始元素,以另一个元素为终止元素的元素子序列的和,并记录找出的子序列和最大的那个值
示例代码如下:
/**
* 用于演示O(N^3)的算法
* @param array 用于寻找最大连续子序列和的数组
* @return 最大连续子序列和的值
*/
public int maxSubN3(int[] array)
{
int result=0;
int length=array.length;
//用于控制子序列的起始下标
for(int i=0;i<length;i++)
{
//用于控制子序列的终止下标
for(int j=i;j<length;j++)
{
//用于计算起始下标到终止下标之间的元素的和
int sum=0;
for(int k=i;k<=j;k++)
{
sum+=array[k];
}
result=Math.max(sum, result);
}
}
return result;
}
第二种:时间复杂度为O(N^2)
该算法通过对上面算法的实现方式进行改进,从而降低了时间复杂度。该算法的思路同上一个的大致相同,但是注意到,每次将终止元素的下标往后移动一位的时候,其子序列和又重新计算了一遍。为此,可以通过保留其上一次从起始元素到终止元素的之间的子序列和的计算结果,来减低时间复杂度。
示例代码如下:
/**
* 用于演示O(N^2)的算法
* @param array 用于寻找最大连续子序列和的数组
* @return 最大连续子序列和的值
*/
public int maxSubN2(int[] array)
{
int length=array.length;
int result=0;
for(int i=0;i<length;i++)
{
int sum=0;
for(int j=i;j<length;j++)
{
sum+=array[j];
result=Math.max(result, sum);
}
}
return result;
}
第三种:时间复杂度为O(NlogN)
采用分治的思想,将数组划分为两半,最大连续子序列和出现的地方只可能有三种,要么在数组的左半边,要么在数组的右半边,要么横跨了数组的左右半边,同时其必定包含数组左半边的右边界以及数组右半边的左边界
/**
* 用于演示O(NlogN)的算法
* @param array 用于寻找最长子序列的数组
* @return
*/
public int maxSubNlogN(int[] array)
{
return maxSubNlogN(array,0,array.length-1);
}
/**
* 用于递归的那个方法,low和high为数组的左右边界
*/
private int maxSubNlogN(int[] array,int low,int high)
{
//当只剩下一个数组元素的时候,将其直接进行返回
if(low==high)
return Math.max(array[low], 0);
//找到数组中间的分界点
int mid=low+(high-low)/2;
//用于寻找到横跨数组左右半边的那个最长子序列
int lMax=0,rMax=0;
int lSum=0,rSum=0;
//找到包含右边界的左半边的最长子序列
for(int i=mid;i>=low;i--)
{
lSum+=array[i];
lMax=Math.max(lSum, lMax);
}
//找到包含左边界的右半边的最长子序列
for(int i=mid+1;i<high;i++)
{
rSum+=array[i];
rMax=Math.max(rSum, rMax);
}
//返回三种情况中子序列和最大的那个值
return Math.max(maxSubNlogN(array,mid+1,high),Math.max(rMax+lMax, maxSubNlogN(array,low,mid)));
}
第三种:时间复杂度为O(N)
由分析可知,数组的最大连续子序列中的包含最大连续子序列的开头元素或者末尾元素的任意一个子序列里的元素值之和均为正数。为此,可以在仅需遍历一遍数组的过程中,计算出其最大连续子序列和
示例代码如下:
/**
* 用于演示O(N)的算法
* @param array 用于寻找最长子序列的数组
* @return 最长子序列的值
*/
public int maxSubN(int[] array)
{
int sum=0;
int result=0;
for(int i=0;i<array.length;i++)
{
sum+=array[i];
if(sum>result)
result=sum;
if(sum<0)
sum=0;
}
return result;
}
代码汇总如下:
package other;
/**
* 该类用于演示寻找最长子序列的几种算法
* @author 学徒
*
*/
public class MaxSubLined
{
public static void main(String[] args)
{
int[] array={-2,11,-4,13,-5,2,-5,-3,12,-9};
MaxSubLined max=new MaxSubLined();
System.out.println(max.maxSubN3(array));
System.out.println(max.maxSubN2(array));
System.out.println(max.maxSubNlogN(array));
System.out.println(max.maxSubN(array));
}
/**
* 用于演示O(N^3)的算法
* 算法的思路:
* 穷举数组中以某个元素为起始的,数组中以该元素为起始元素的所有子序列的可能
* 并找出其中子序列和最大的那个值
* @param array 用于寻找最长子序列的数组
* @return 最长子序列的值
*/
public int maxSubN3(int[] array)
{
int result=0;
int length=array.length;
//用于控制子序列的起始下标
for(int i=0;i<length;i++)
{
//用于控制子序列的终止下标
for(int j=i;j<length;j++)
{
//用于计算起始下标到终止下标之间的元素的和
int sum=0;
for(int k=i;k<=j;k++)
{
sum+=array[k];
}
result=Math.max(sum, result);
}
}
return result;
}
/**
* 用于演示O(N^2)的算法
* 算法的思路:
* 穷举数组中以某个元素为起始的,数组中以该元素为起始元素的所有子序列的可能
* 并找出其中子序列和最大的那个值
* @param array 用于寻找最长子序列的数组
* @return 最长子序列的值
*/
public int maxSubN2(int[] array)
{
int length=array.length;
int result=0;
for(int i=0;i<length;i++)
{
int sum=0;
for(int j=i;j<length;j++)
{
sum+=array[j];
result=Math.max(result, sum);
}
}
return result;
}
/**
* 用于演示O(NlogN)的算法
* 算法的思路:
* 采用分治的思想,将数组划分为两半,最长子序列出现的可能只有三种
* 要么在数组的左半边,要么在数组的右半边,要么横跨了数组的左右半边,同时其必定包含
* 数组左半边的右边界以及数组右半边的左边界
* @param array 用于寻找最长子序列的数组
* @return
*/
public int maxSubNlogN(int[] array)
{
return maxSubNlogN(array,0,array.length-1);
}
/**
* 用于递归的那个方法,low和high为数组的左右边界
*/
private int maxSubNlogN(int[] array,int low,int high)
{
//当只剩下一个数组元素的时候,将其直接进行返回
if(low==high)
return Math.max(array[low], 0);
//找到数组中间的分界点
int mid=low+(high-low)/2;
//用于寻找到横跨数组左右半边的那个最长子序列
int lMax=0,rMax=0;
int lSum=0,rSum=0;
//找到包含右边界的左半边的最长子序列
for(int i=mid;i>=low;i--)
{
lSum+=array[i];
lMax=Math.max(lSum, lMax);
}
//找到包含左边界的右半边的最长子序列
for(int i=mid+1;i<high;i++)
{
rSum+=array[i];
rMax=Math.max(rSum, rMax);
}
//返回三种情况中子序列和最大的那个值
return Math.max(maxSubNlogN(array,mid+1,high),Math.max(rMax+lMax, maxSubNlogN(array,low,mid)));
}
/**
* 用于演示O(N)的算法
* 算法的思路:
* 因为最长子序列中的任意一个子序列里的元素值总和均为正数
* 为此,可以在遍历数组的过程中,计算出其最长子序列
* @param array 用于寻找最长子序列的数组
* @return 最长子序列的值
*/
public int maxSubN(int[] array)
{
int sum=0;
int result=0;
for(int i=0;i<array.length;i++)
{
sum+=array[i];
if(sum>result)
result=sum;
if(sum<0)
sum=0;
}
return result;
}
}
K:求取数组中最大连续子序列和的四个算法的更多相关文章
- 求一个数组中最小的K个数
方法1:先对数组进行排序,然后遍历前K个数,此时时间复杂度为O(nlgn); 方法2:维护一个容量为K的最大堆(<算法导论>第6章),然后从第K+1个元素开始遍历,和堆中的最大元素比较,如 ...
- python实现给定K个字符数组,从这k个字符数组中任意取一个字符串,按顺序拼接,列出所有可能的字符串组合结果!
题目描述:给定K个字符数组,从这k个字符数组中任意取一个字符串,按顺序拼接,列出所有可能的字符串组合结果! 样例: input:[["a","b"," ...
- 转载——JavaScript学习笔记:取数组中最大值和最小值
转载自:http://www.w3cplus.com/javascript/calculate-the-max-min-value-from-an-array.html. 取数组中最大值 可以先把思路 ...
- JavaScript学习:取数组中最大值和最小值
在实际业务中有的时候要取出数组中的最大值或最小值.但在数组中并没有提供arr.max()和arr.min()这样的方法.那么是不是可以通过别的方式实现类似这样的方法呢?那么今天我们就来整理取出数组中最 ...
- 求出数组中所有数字的和&&弹出层效果
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/ ...
- 黑马基础阶段测试题:定义一个int类型的数组,数组中元素为{5,7,3,9,4}。求出数组中的最小值,并判断最小值是否为偶数,如果是偶数则输出“最小值为偶数”,如果不是偶数则输出“最小值为奇数”。打印如下:
package com.swift; import java.util.Arrays; public class ArrayTest { public static void main(String[ ...
- 《程序员代码面试指南》第七章 位运算 在其他数都出现k 次的数组中找到只出现一次的数
题目 在其他数都出现k 次的数组中找到只出现一次的数 java 代码 package com.lizhouwei.chapter7; /** * @Description: 在其他数都出现k 次的数组 ...
- 如何求出数组中最小(或者最大)的k个数(least k问题)
输入n个整数,如何求出其中最小的k个数? 解法1. 当然最直观的思路是将数组排序,然后就可以找出其中最小的k个数了,时间复杂度以快速排序为例,是O(nlogn): 解法2. 借助划分(Partitio ...
- [LeetCode] Split Array into Consecutive Subsequences 将数组分割成连续子序列
You are given an integer array sorted in ascending order (may contain duplicates), you need to split ...
随机推荐
- Postgres中的SpinLock锁
我们知道,在数据库中为了并发控制,少不了要使用各种各样的锁(lock).PostgreSQL中也不例外. 在PostgreSQL中有三种级别的锁,他们的关系如下: |上层 RegularLock | ...
- 在 Go 语言中使用 Log 包--转自GCTT
Linux 在许多方面相对于 Windows 来说都是独特的,在 Linux 中编写程序也不例外.标准输出,标准 err 和 null devices 的使用不仅是一个好主意,也是一个原则.如果您的程 ...
- Python:学习遇到的小问题:记事本写的脚本执行提示SystaxError:(unicode error) 'utf-8'
学习了一段时间的Python因为懒没有坚持,现在又想学,在用记事本写好py脚本运行时报错:SystaxError:(unicode error) 'utf-8' 解决的方法: 因为我的笔记本系统自带的 ...
- Java NIO学习与记录(七): Reactor单线程模型的实现
Reactor单线程模型的实现 一.Selector&Channel 写这个模型需要提前了解Selector以及Channel,之前记录过FileChannel,除此之外还有以下几种Chann ...
- 【编程技术-Shell】AWK使用大全
1. AWK中输出特殊字符 输出单引号 涉及到转义字符,但是在使用普通的方法进行转义时,会遇到下面的问题 正确的方法:'\'',使用单引号将转义字符括起来,然后后面加上单引号 输出其他特殊字符 输出 ...
- Springboot用官方建议访问Html页面并接传值
Springboot用官方建议访问Html页面并接传值 我们以前通常习惯用webapp来防止jsp页面,但是到了Springboot中,官方建议用Static文件夹来存放及静态的资源, 用templa ...
- spring使用@Value注解读取.properties文件时出现中文乱码问题的解决
解决办法 在spring中我们常常使用.properties对一些属性进行一个提前配置, spring 在读取*.properties文件时, 默认使用的是asci码, 这时 我们需要对其编码进行转换 ...
- JMS、AMQP和MQTT主要特性
今天无意中看到mq的原理,才发现activeMq与ribbMq的原理是不一样的.前者是JMS的实现,后者是AMQP的实现... 原理简介:https://www.cnblogs.com/zhangyu ...
- java.lang.IllegalArgumentException: Comparison method violates its general contract!
这个错误就是写比较器的时候少写了返回值的情况: 比如: Collections.sort(list, new Ordering<QtmSysUserListDto>() { @Overri ...
- JVM的类加载时机
类加载过程中每个步骤的顺序 我们已经知道,类加载的过程包括:加载.连接.初始化,连接又分为:验证.准备.解析,所以说类加载一共分为5步:加载.验证.准备.解析.初始化. 其中加载.验证.准备.初始化的 ...