求数组最大平均值的连续子序列、最大和的连续子序列

算法是我最头疼的问题,经常被问到就懵逼,但是后来一想就能想起来,也是没那么能难,人啊就是要多总结,人类的进步就是因为人把知识记载了下来,后来的人有了前人的经验教训,总会成长,慢慢成长。在岁月的长河中,知识达到了沉淀,孕育了很多伟大的民族文化。。。

实在编不下去了,赶紧进入正题,同学啊,在你看到题目的时候也是一脸懵逼,如果是的话,那就对了,证明你没看过类似的算法,看到题目有种似懂非懂的感觉,光是理解题目就是很费劲,没错,因为这个题就是考的脑筋急转弯?啥,不明白啊,等我说完你就知道了。。。

还在扯什么啊,怎么还不进入正题呢?很多人肯定要骂我了,其实 我是留给大家思考的时间,因为大家再看这段废话的时候大脑却在想着我的问题,为什么我·会这么说,哈哈 我看过最强大脑,去年这个的时候,我因为最强大脑,花了一个月的时间专门去训练了记忆力,你还别说,还真有效果。我先练习的定桩,110数字桩,懂的同学知道我在说什么,不懂的同学我也不会在这说了,给你个传送门,好吧开始进入正题吧。

package zong.xiao.mi.demosource.java;

/**
 * Created by mi on 2017/4/5.
 */

public class 最大平均值的连续子序列 {


  public static int[] array = {-2, 3, -5, 4, 1, -1, 2};

  public static void main(String[] arguments) {
    maxAverage(array);
    maxSum(array);
  }



  /**
   * 求数组的最大平均值的连续子序列(连续子序列:元素个数大于等于2)
   * 
   * @return
   */
  public static int[] maxAverage(int[] array) {

    int length = array.length;
    int sum;
    float currentAvg = 0;// 当前的平均值
    int markI = 0;// 标记连续子序列的起始下标
    int markJ = 0;// 标记连续子序列的结束下标
    for (int i = 0; i < length; i++) {
      sum = 0;// 重置sum
      for (int j = i; j < length; j++) {
        sum = sum + array[j];// 累积求和
        float avg = (float) sum / (j - i + 1);
        if (avg > currentAvg && i != j) {// 如果起始下标等于结束下标,就是表明是单个元素,此块要排除
          markJ = j;
          markI = i;
          currentAvg = avg;
        }
      }
    }
    int arr[] = new int[markJ - markI + 1];
    System.arraycopy(array, markI, arr, 0, markJ - markI + 1);

    System.out.println("最大平均值==" + currentAvg + "-在数组中的起始位置==" + markI + "-数组中的结束位置==" + markJ);
    return arr;
  }

  /**
   * 最大和的连续子序列
   * 时间复杂度O(N^2)
   * @param array
   * @return
   */
  public static int[] maxSum(int array[]) {
    if (array == null || array.length == 0) return null;
    int length = array.length;
    int sum = 0;
    int currentSum = 0;
    int markStart = 0;
    int markEnd = 0;

    for (int i = 0; i < length; i++) {
      sum = 0;
      for (int j = i; j < length; j++) {
        sum += array[j];
        if (sum > currentSum) {
          markStart = i;
          markEnd = j;
          currentSum = sum;
        }
      }
    }
    int[] copy = new int[markEnd - markStart + 1];
    System.arraycopy(array, markStart, copy, 0, markEnd - markStart + 1);
    System.out
        .println("最大和==" + currentSum + "-在数组中的起始位置==" + markStart + "-数组中的结束位置==" + markEnd);
    return copy;
  }
}



多么简单粗暴,代码自己看吧,注释都在上面。
补充求和的第二种方法,性能更优。

/**
   * 最大和的连续子序列第二种方法
   *
   * 时间复杂度O(N)
   * 
   * @param array
   * @return
   */
  public static int[] maxSum2(int array[]) {

    int temp = 0;
    int currentMax = 0;
    int length = array.length;
    int start = 0;// 标记开始位置
    int end = 0;// 标记结束位置

    for (int i = 0; i < length; i++) {
      if (temp + array[i] > 0) {
        temp = temp + array[i];
      } else {
        temp = 0;
        start = i + 1;
      }

      if (temp > currentMax) {
        end = i;
        currentMax = temp;
      }
    }
    System.out.println(currentMax + "start==" + start + "end==" + end);
    return null;
  }

第二个算法的时间复杂度最好,只用了一遍遍历

说个注意的点,什么是连续子序列,我认为啊这个连续子序列的元素的个数要大于两个才能算连续子序列。如果没有这个限制会怎么样?
如果没有这个限制,上边数组中的最大连续子序列 我不用算就知道是4 ,我不相信哪个子序列的平均值会大于4,为什么,因为任何一个数,加上比自己小的数,再求平均值,肯定没有这个数大。如果有这个限制,那就从所有含有两个元素的子序列里面找。因为三个数的平均值肯定没有两个的数的平均值大。如果这几个元素都是一样大小值的 你就别给我扯淡了。。

最大平均值的连续子序列: 求出数组所有的连续子序列,对每个连续子序列求平均值,找最大的一个。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

  • Android 自定义View的各种姿势1 Activity的显示之ViewRootImpl详解 Activity...
    passiontim阅读 175,327评论 25 709
  • 题目描述 给定n个数的数组,找到所有长度大于等于k的连续子数组中平均值最大的那个。返回那个最大的平均值。 1 <=...
    HITMiner阅读 9,721评论 0 1
  • 前言 其实读完斯坦福的这本《互联网大规模数据挖掘》,让我感觉到,什么是人工智能?人工智能就是更高层次的数据挖掘。机...
    我偏笑_NSNirvana阅读 14,378评论 1 23
  • 像我这样懒散,且又没有责任感的人,最大的愿望,便是不用工作,也不用理会俗世的那些繁文礼节,每天只是把自己收拾的干干...
    成誠师兄阅读 1,365评论 0 0
  • 辛苦了大半辈子 汗水和青春都留在了黑土地上 在夕阳的余晖里 我想明白了 总该为自己做点什么吧 约上山羊一家和唱...
    云淡风轻之蓝阅读 3,680评论 41 44