有什么办法可以解决nlogn复杂性的问题

时间:2020-04-14 22:03:39

标签: java algorithm

您将获得由A [1],A [2] ..... A [N]表示的N个整数A的序列。 序列中的每个整数都有一个与之关联的值W [1],W [2]…。 W [N]。 您必须选择给定数组A的子序列,以使A中的所有元素严格按递增顺序排列,并且此选定子序列中的元素值之和最大。您必须打印此最大值。

样本输入

2  
4  
1 2 3 4  
100 200 300 400  
3  
4 2 3  
100 30 20   

样本输出

1000   
100     

我尝试使用动态编程解决此问题,但是我的代码的时间复杂度为n ^ 2,所以我想将其复杂度降低为nlogn,您能帮我吗?

这是我的实现方式

public class testing {
    public static void main(String[] args) {
        Scanner scn = new Scanner(System.in);
        int t = scn.nextInt();
        StringBuilder sb = new StringBuilder();
        while (t-- > 0) {
            int n = scn.nextInt();
            int a[] = new int[n];
            long val[] = new long[n];
            for (int i = 0; i < n; i++) {
                a[i] = scn.nextInt();
            }
            for (int i = 0; i < n; i++) {
                val[i] = scn.nextLong();
            }

            long dp[] = new long[n];
            Arrays.fill(dp, Integer.MIN_VALUE);
            dp[0] = val[0];
            for (int i = 1; i < n; i++) {
                for (int j = i - 1; j >= 0; j--) {
                    if (a[j] < a[i]) {
                        dp[i] = Math.max(dp[i], dp[j] + val[i]);
                    }
                }
            }
            long ans = Integer.MIN_VALUE;
            for (long v : dp) {
                ans = Math.max(v, ans);
            }
            sb.append(ans + "\n");
        }
        System.out.println(sb);
    }
}

由于违规,我获得了TLE

约束 1 <= T <= 5 1 <= N <= 200000 1 <= a [i] <= 10 ^ 9,其中i∈[1..N] 1 <= w [i] <= 10 ^ 9,其中i∈[1..N]

1 个答案:

答案 0 :(得分:2)

迭代一次,对于小于或等于给定A的A值,保持W值之和的TreeMap,如对A值进行迭代时看到的那样。

对于新的A,请调用lowerEntry(key)方法以获取低于该新A的W的总和。

记住最大金额,然后将其返回。

单次迭代为 O(n)TreeMap的使用为 O(log n),因此解决方案为 O(n log n ) *

static int sumIncreasing(int[] a, int[] w) {
    int maxSum = Integer.MIN_VALUE;
    TreeMap<Integer, Integer> sums = new TreeMap<>();
    for (int i = 0; i < a.length; i++) {
        Entry<Integer, Integer> lowerSum = sums.lowerEntry(a[i]);
        int sum = (lowerSum != null ? lowerSum.getValue() + w[i] : w[i]);
        sums.put(a[i], sum);
        for (Entry<Integer, Integer> e; (e = sums.higherEntry(a[i])) != null && e.getValue() <= sum; )
            sums.remove(e.getKey());
        if (sum > maxSum)
            maxSum = sum;
    }
    return maxSum;
}

*)内部for循环为O(log n)(分期偿还,最坏的情况),因此它不会影响整体复杂性。 < / p>

测试

System.out.println(sumIncreasing(new int[] {1, 2, 3, 4}, new int[] {100, 200, 300, 400}));
System.out.println(sumIncreasing(new int[] {4, 2, 3}, new int[] {100, 30, 20}));

输出

1000
100