任务是计算任何数组元素右侧不同小元素的最大数量

时间:2020-03-30 04:36:28

标签: java arrays binary-search-tree treeset

例如,在{10,6,9,7,20,19,21,18,17,16}中,结果为4。请注意,20在右侧最多具有4个较小的元素。其他元素的数量较少,例如10个元素的右侧有3个较小的元素。

import java.util.*;
import java.io.*;

class GSOR {
public static int getMaxSmallerOnRight(int[] arr, int n) {
    int count = 0;
    TreeSet<Integer> set = new TreeSet<Integer>();
    for (int index = n - 1; index >= 0; --index) {
        set.add(arr[index]);
        count = Math.max(count, set.headSet(arr[index]).size());
    }
    return count;
}
public static void main (String[] args) {
   Scanner sc=new Scanner(System.in);
    int t = sc.nextInt();
    while(t-->0){
        int n= sc.nextInt();
        int[] arr = new int[n];
        for(int i=0; i<n; i++){
            arr[i]= sc.nextInt();
        }
        System.out.println(getMaxSmallerOnRight(arr, n));
    }
}
}

如何优化此代码?我的目标是不到4.192秒。

1 个答案:

答案 0 :(得分:1)

我们可以使用分而治之的东西,这是一个示例,我没有完全证明结果是正确的,但是我相信您可以改进更多,

 public class GSOR extends RecursiveTask<Integer> {

    private int[] arr;
    private int start;
    private int end;

    public GSOR(int[] arr, int start, int end) {

        if (end < start) {
            throw new IllegalArgumentException("end < start");
        }

        this.arr = arr; // we do not modify the original array, 
                        // so ref-var is OK here
        this.start = start;
        this.end = end;
    }

    @Override
    protected Integer compute() {

        // decide if we divide the computation by two
        int middle = (end - start) / 2;
        if (middle > 1) {
            // fork the first half and start another task for it
            ForkJoinTask<Integer> rightTask = new GSOR(arr, start, start + middle);
            rightTask.fork();

            return Math.max(
                    // just compute the second half part and find the max of them
                    new GSOR(arr,  start + middle + 1, end).compute(), 
                    rightTask.join()); // wait for first half's computation
        }

        // the items we need to deal are small enough to compute
        int max = 0;
        for (int i = start; i <= end; i++) {
            // no duplicate item please 
            Set<Integer> minSets = new HashSet<>();
            // it could be a long way to go if start is really beginning of the start
            // if N goes to very big number we consider to divide this computation also
            for (int j = i + 1; j < arr.length; j++) {
                if (arr[i] > arr[j]) {
                    minSets.add(arr[j]);
                }
            }
            max = Math.max(max, minSets.size());
        }

        return max;

    }

    private static ForkJoinPool fjPool = new ForkJoinPool();

    public static void stop() {

        fjPool.shutdown();

        try {
            fjPool.awaitTermination(30, TimeUnit.SECONDS);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

    } 

    public static void submit(int[] arr) {

        if (null == arr || arr.length < 3) {
            // i can do this on my mind
            return;
        }

        for(int i = 0; i < arr.length; i++) {
            System.out.print(arr[i] + ", ");
        }
        System.out.println();

        Future<Integer> result = fjPool.submit(new GSOR(arr, 0, arr.length));
        try {
            System.out.println(result.get(5, TimeUnit.SECONDS));
        } catch (InterruptedException | ExecutionException | TimeoutException e) {
            e.printStackTrace();
        }
    }   
}

这是测试人员;

    public class StackOverflowMain {

    public static void main(final String[] args) {

        for (int lmt = 4; lmt < 20; lmt += 3) {
            int[] ints = Stream
                    .generate(()->Integer.valueOf((int)(Math.random()*1000)))
                    .limit(lmt)
                    .mapToInt(i -> i)
                    .toArray();

            GSOR.submit(ints);
        }

    int[] arr = new int[]{10, 6, 9, 7, 20, 19, 21, 18, 17, 16};
    GSOR.submit(arr);

        GSOR.stop();

    }
}