【问题标题】:The task is to count maximum number of distinct smaller elements on right side of any array element任务是计算任何数组元素右侧不同较小元素的最大数量
【发布时间】:2020-03-30 04:36:28
【问题描述】:

例如,在 {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 秒。

【问题讨论】:

    标签: java arrays binary-search-tree treeset


    【解决方案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();
    
        }
    }
    

    【讨论】:

    • 当数组大小小于 10K 时,我们似乎可以得到相当不错的结果,但是包含 100K 项的数组结果非常糟糕,我们肯定会优化计算方法中的第二个 for 循环
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-05-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-07-19
    • 2022-12-31
    相关资源
    最近更新 更多