ICode9

精准搜索请尝试: 精确搜索
首页 > 编程语言> 文章详细

java-使用RangeMap时相交范围

2019-10-26 11:00:34  阅读:103  来源: 互联网

标签:guava java


我遇到了类似的问题

您正在维护对冲基金的交易平台.对冲基金的交易员全天执行交易策略.
为了简单起见,我们假设每种交易策略在运行期间的总收益为英镑/分钟.我可以是负面的.
最终,您将看到一个如下所示的日志文件:

> timestamp_start_1,timestamp_end_1,i_1
> timestamp_start_2,timestamp_end_2,i_2
> timestamp_start_3,timestamp_end_3,i_3

每行代表该策略何时开始执行,何时停止以及以比率产生的收入.
编写一些代码以返回对冲基金每分钟赚钱最多的那一天的时间.

例子:

输入:

>(1、13、400)
>(10、20、100)

结果:

>(10,13)500

输入:

>(12,14,400)
>(10,20,100)

结果:

>(12,14)500

输入:

>(10、20、400)
>(21,25,100)

结果:

>(10,20)400

我一直在尝试使用番石榴RangeMap来解决它,但是没有明显的方法来交叉重叠的间隔.

例如:

private static void method(Record[] array){
    RangeMap<Integer, Integer> rangeMap = TreeRangeMap.create();
    for (Record record : array) {
        rangeMap.put(Range.closed(record.startTime, record.endTime), record.profitRate);
    }
    System.out.println(rangeMap);   
}

public static void main(String[] args) {
    Record[] array = {new Record(1,13,400), new Record(10,20,100)};
    method(array);
}

地图看起来像:
[[1..10)= 400,[10..20] = 100]

是否有任何方法可以覆盖重叠行为或任何其他可用于解决问题的数据结构?

解决方法:

如评论中所述:RangeMap可能不适合此操作,因为RangeMap的范围必须不相交.

评论中提到了一种通常可以解决此问题的方法:一种方法可以组合所有范围,并据此生成所有不相交的范围.例如,给定这些范围

  |------------|       :400
           |----------|:100

一个人可以计算出交集所隐含的所有子范围

  |--------|           :400
           |---|       :500
               |------|:100

在这种情况下,中间的范围显然是解决方案.

但总的来说,问题陈述中存在一些不足.例如,尚不清楚多个范围是否可以具有相同的开始时间和/或相同的结束时间.与可能的优化相关的事情可能是记录是否以任何方式“排序”.

但是无论如何,一种通用方法可能如下:

>计算从所有开始时间到从那里开始的记录的映射
>计算从所有结束时间到结束时间的记录的映射
>按顺序遍历所有开始和结束时间,跟踪当前时间间隔的累计利润率

(是的,这基本上是根据注释生成不相交集的方法.但是,它并不“构造”包含此信息的数据结构.它只是使用此信息来动态地计算最大值).

一个实现可能看起来像这样:

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.TreeSet;

class Record
{
    int startTime;
    int endTime;
    int profitRate;

    public Record(int startTime, int endTime, int profitRate)
    {
        this.startTime = startTime;
        this.endTime = endTime;
        this.profitRate = profitRate;
    }

    @Override
    public String toString()
    {
        return "(" + startTime + "..." + endTime + ", " + profitRate + ")";
    }

}

public class MaxRangeFinder
{
    public static void main(String[] args)
    {
        test01();
        test02();
    }

    private static void test01()
    {
        System.out.println("Test case 01:");
        Record[] records = {
            new Record(1,13,400), 
            new Record(10,20,100),
        };
        Record max = computeMax(Arrays.asList(records));
        printNicely(Arrays.asList(records), max);
    }

    private static void test02()
    {
        System.out.println("Test case 02:");
        Record[] records = {
            new Record(1,5,100), 
            new Record(2,6,200),
            new Record(3,4,50),
            new Record(3,4,25),
            new Record(5,8,200),
        };
        Record max = computeMax(Arrays.asList(records));
        printNicely(Arrays.asList(records), max);
    }


    private static Record computeMax(Collection<? extends Record> records)
    {
        // Create mappings from the start times to all records that start 
        // there, and from the end times to the records that end there 
        Map<Integer, List<Record>> recordsByStartTime =
            new LinkedHashMap<Integer, List<Record>>();
        for (Record record : records)
        {
            recordsByStartTime.computeIfAbsent(record.startTime,
                t -> new ArrayList<Record>()).add(record);
        }
        Map<Integer, List<Record>> recordsByEndTime =
            new LinkedHashMap<Integer, List<Record>>();
        for (Record record : records)
        {
            recordsByEndTime.computeIfAbsent(record.endTime,
                t -> new ArrayList<Record>()).add(record);
        }

        // Collect all times where a record starts or ends
        Set<Integer> eventTimes = new TreeSet<Integer>();
        eventTimes.addAll(recordsByStartTime.keySet());
        eventTimes.addAll(recordsByEndTime.keySet());

        // Walk over all events, keeping track of the 
        // starting and ending records
        int accumulatedProfitRate = 0;
        int maxAccumulatedProfitRate = -Integer.MAX_VALUE;
        int maxAccumulatedProfitStartTime = 0;
        int maxAccumulatedProfitEndTime = 0;

        for (Integer eventTime : eventTimes)
        {
            int previousAccumulatedProfitRate = accumulatedProfitRate;

            // Add the profit rate of the starting records
            List<Record> startingRecords = Optional
                .ofNullable(recordsByStartTime.get(eventTime))
                .orElse(Collections.emptyList());
            for (Record startingRecord : startingRecords)
            {
                accumulatedProfitRate += startingRecord.profitRate;
            }

            // Subtract the profit rate of the ending records
            List<Record> endingRecords = Optional
                .ofNullable(recordsByEndTime.get(eventTime))
                .orElse(Collections.emptyList());
            for (Record endingRecord : endingRecords)
            {
                accumulatedProfitRate -= endingRecord.profitRate;
            }

            // Update the information about the maximum, if necessary
            if (accumulatedProfitRate > maxAccumulatedProfitRate)
            {
                maxAccumulatedProfitRate = accumulatedProfitRate;
                maxAccumulatedProfitStartTime = eventTime;
                maxAccumulatedProfitEndTime = eventTime;
            }
            if (previousAccumulatedProfitRate == maxAccumulatedProfitRate &&
                accumulatedProfitRate < previousAccumulatedProfitRate)
            {
                maxAccumulatedProfitEndTime = eventTime;
            }
        }

        return new Record(
            maxAccumulatedProfitStartTime, 
            maxAccumulatedProfitEndTime, 
            maxAccumulatedProfitRate);

    }



    private static void printNicely(
        Collection<? extends Record> records, 
        Record max)
    {
        StringBuilder sb = new StringBuilder();
        int maxEndTime =  Collections.max(records, 
            (r0, r1) -> Integer.compare(r0.endTime, r1.endTime)).endTime;
        for (Record record : records)
        {
            sb.append("     ")
                .append(createString(record, maxEndTime))
                .append("\n");
        }
        sb.append("Max: ").append(createString(max, maxEndTime));
        System.out.println(sb.toString());
    }

    private static String createString(Record record, int maxEndTime)
    {
        StringBuilder sb = new StringBuilder();
        int i = 0;
        while (i < record.startTime)
        {
            sb.append(" ");
            i++;
        }
        sb.append("|");
        while (i < record.endTime)
        {
            sb.append("-");
            i++;
        }
        sb.append("|");
        while (i < maxEndTime)
        {
            sb.append(" ");
            i++;
        }
        sb.append(":").append(record.profitRate);
        return sb.toString();
    }
}

代码中给出的两个测试用例的输出是

Test case 01:
      |------------|       :400
               |----------|:100
Max:           |---|       :500

Test case 02:
      |----|   :100
       |----|  :200
        |-|    :50
        |-|    :25
          |---|:200
Max:      |-|  :400

标签:guava,java
来源: https://codeday.me/bug/20191026/1936150.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有