• 使用分治思想求解最大子序列


           本文使用分治思想求解一个整型数组中的最大子序列,该算法的时间复杂度为NlogN,使用千万级的数据量计算结果的时间不超过0.5s。该算法使用了分治的思想:求解最大子序列的问题可以理解为将整个数组分成左右两部分,分别求解左边和 右边的最大子序列,并且还有一种情况是最大子序列在中间,此时可以可以直接从中间开始分别向左和向右遍历求解左右两边的最大子序列(由于此时假定最大子序列在中间,因而中间的元素肯定在最大子序列中),然后将两边的最大子序列相加就会得到最大子序列在中间时的子序列,此时当前数组就会有三个(左边,右边和中间)已经求得的最大子序列,现只需要比较这三个子序列的和即可,将最大和返回。具体的算法如下:

    public class Solution {
    
      public long findMaxSubSequence(Integer[] arr) { //
        return maxSumRec(arr, 0, arr.length - 1);
      }
    
      // 求解最大子序列函数
      private long maxSumRec(Integer[] arr, int left, int right) {
        // 递归调用的出口
        if (left == right) {
          return arr[left];
        }
    
        // 分别计算左边和右边的最大子序列
        int center = (left + right) / 2;
        long maxLeftSum = maxSumRec(arr, left, center);
        long maxRightSum = maxSumRec(arr, center + 1, right);
    
        // 计算中间的最大子序列的左半部分的最大值
        int maxLeftBorderSum = 0, leftBorderSum = 0;
        for (int i = center; i >= left; i--) {
          leftBorderSum += arr[i];
          if (leftBorderSum > maxLeftBorderSum) {
            maxLeftBorderSum = leftBorderSum;
          }
        }
    
        // 计算中间的最大子序列的右半部分的最大值
        int maxRightBorderSum = 0, rightBorderSum = 0;
        for (int i = center + 1; i <= right; i++) {
          rightBorderSum += arr[i];
          if (rightBorderSum > maxRightBorderSum) {
            maxRightBorderSum = rightBorderSum;
          }
        }
    
        return max(maxLeftSum, maxRightSum, maxLeftBorderSum + maxRightBorderSum);
      }
    
      // 求解三个值中的最大值
      private long max(long maxLeftSum, long maxRightSum, int maxBorderSum) {
        return maxLeftSum >= maxRightSum && maxLeftSum >= maxBorderSum ? maxLeftSum : (maxRightSum > maxBorderSum ? maxRightSum : maxBorderSum);
      }
    }

            具体的实验程序如下:

    import java.util.Date;
    import java.util.Random;
    
    public class App {
      public static void main(String[] args) {
        Integer[] arr = new Integer[10000000];
        for (int i = 0; i < 10000000; i++) {
          arr[i] = new Random().nextInt();
        }
        Solution solution = new Solution();
        Long start = new Date().getTime();
        long result = solution.findMaxSubSequence(arr);
        Long end = new Date().getTime();
        System.out.println("结果为:" + result);
        System.out.print("所用时长为:" + (end - start));
      }
    }
    

            运行结果如下:

    计算结果为:2147483164
    所用时长为:447
    Process finished with exit code 0

            

           这是计算最大子序列的一种算法,现贴出一种更为完美的方法,其时间复杂度为O(N),代码量也得到了大大的简化,代码如下:

    public class Solution {
      public long findMaxSubSequence(Integer[] arr) {
        long maxSum = 0, thisSum = 0;
        for (int i = 0; i < arr.length; i++) {
          thisSum += arr[i];
          if (thisSum > maxSum) {
            maxSum = thisSum;
          } else if (thisSum < 0){
            thisSum = 0;
          }
        }
        return maxSum;
      }
    }

            由于本人也不甚理解,现只将代码帖于此处。

     

  • 相关阅读:
    poj 3304 Segments 直线 线段求交
    poj 1077 Eight 八数码 A*算法
    UESTC 1447 Area 凸包+旋转卡壳 求最大四边形面积
    ACM计算几何题目推荐(第二期)
    poj 2398 Toy Storage 叉乘
    ACM计算几何题目推荐 (第一期)
    (转载)Telnet协议详解及使用C# 用Socket 编程来实现Telnet协议
    jquery 表情编辑器
    (读书笔记)Asp.net Mvc 与WebForm 混合开发
    (转载)精简说明C#最基本的Socket编程示例
  • 原文地址:https://www.cnblogs.com/zhangxufeng/p/8284067.html
Copyright © 2020-2023  润新知