通过执行最多K个交换可以获得的最小连续总和

时间:2016-04-02 06:05:18

标签: arrays algorithm sum dynamic-programming minimum

我有这个功课:

  

给定一个由N整数组成的数组,您需要打印最多可以通过执行K个交换获得的最小连续总和。在交换期间,可以交换给定数组的任何2个元素。

我试过这个

int currentSum = 0;
int currentMin = 0;

for (int j = 0; j < input.Length; j++)
{
    if (input[j] >= 0)
        continue;
    currentSum += input[j];

    if (currentMin > currentSum)
        currentMin = currentSum;
}

它会在没有任何交换的情况下给出最小金额,但如何在不超过K掉期的情况下改善?

2 个答案:

答案 0 :(得分:2)

import java.io.BufferedReader;
import java.io.InputStreamReader;

import java.util.Collections;
import java.util.Iterator;
import java.util.PriorityQueue;
import java.util.Scanner;
import java.util.ArrayList;
import java.util.List;


class TestClass {

       static Scanner scanner;
        public static void main(String args[] ) throws Exception {


        scanner=new Scanner(System.in);
        int T=scanner.nextInt();

        while(T>0){
        int N=scanner.nextInt();
        int K=scanner.nextInt();
        int[] array=new int[N];
         for(int i=0;i<array.length;i++)
         {
            array[i]=scanner.nextInt();
        }


         System.out.println(findingMinimumSumSubarray(array, K));

            T--;
        }


    }

    public static int findingMinimumSumSubarray(int[] values, int k) {
     int N = values.length;
     int res = values[0]; 
     for (int L = 0; L < N; L++) {
         for (int R = L; R < N; R++) {
             List<Integer> A= new ArrayList<Integer>();
             List<Integer> B = new ArrayList<Integer>(); 
             int ashu = 0; 
             for (int i = 0; i < N; i++) {
                 if (i >= L && i <= R) {
                  A.add(values[i]);
                     ashu += values[i];
                 } else {
                     B.add(values[i]);
                 }
             }

             Collections.sort(A);

             Collections.sort(B);
             Collections.reverse(B);
             res = Math.min(res, ashu); 
             for (int t = 1; t <= k; t++) {

                 if (t > A.size() || t > B.size()) break;

                 ashu -= A.get(A.size() - t);
                 ashu += B.get(B.size() - t);
                 res = Math.min(res, ashu);
             }
         }
     }
     return res;
 }
}

答案 1 :(得分:0)

即使没有交换,您的解决方案也不正确。

  

测试:[-1,2,-1]。你对这个测试的答案是-2。正确答案:-1

我希望我的解决方案不是最好的,并且有更好的方法。

简单的O(N ^ 3)复杂性解决方案。

假设我们的最终最小连续段将是[L,R],对于某些0 <= L&lt; = R&lt; N.现在我们有两个multiset:A和B. A - 具有“内部”数字的多重集(数字在[L,R]范围内)和B - 具有“外部”数字的多重集(数字超出范围[L] ,R])。目标是最小化A - sum(A)中的数字总和。在A或B内部进行交换是有意义的,因为它不会影响sum(A)。我们可以将A中的一个元素与B中的其他元素交换。我们只有K个交换,这意味着A中不超过K个元素将与B中不超过K个元素交换。达到最小值和(A)我们将在A中取一些最大元素并用B中的最小元素交换它们。例如:

  

A = { - 3,-3,-1,2}; B = { - 4,1,3,6}; K = 2;

     
      
  • 我们可以进行0次交换,A = { - 3,-3,-1,2}; B = { - 4,1,3,6};然后总和(A)== -3
  •   
  • 我们可以进行1次交换,A = { - 3,-3,-1,-4}; B = {2,1,3,6};然后总和(A)== -11
  •   
  • 我们可以进行2次交换,A = { - 3,-3,1,-4}; B = {2,-1,3,6};然后总和(A)== -9
  •   
     

答案是总和(A)== -11

对于范围[L,R],我们可以获得最小可能的总和。为了获得我们最初问题的答案,我们将迭代所有可能的范围[L,R]。 0 <= L&lt; = R&lt; Ñ

天真的实施。 O(N ^ 3logn)复杂性。

int get_minimum_contiguous_sum(vector <int> values, int k) {
    int N = values.size();
    int ans = values[0]; // initializing with any possible sums
    for (int L = 0; L < N; L++) {
        for (int R = L; R < N; R++) {
            vector <int> A, B; // our "inner" and "outer" sets
            int suma = 0; // will store initial sum of elements in A
            for (int i = 0; i < N; i++) {
                if (i >= L && i <= R) {
                    A.push_back(values[i]);
                    suma += values[i];
                } else {
                    B.push_back(values[i]);
                }
            }
            // Sorting set A in non-descending order
            sort(A.begin(), A.end());
            // Sorting set B in non-increasing order
            sort(B.begin(), B.end());
            reverse(B.begin(), B.end());
            ans = min(ans, suma); // Updating answer with initial state
            // Iterating number of swaps that we will make
            for (int t = 1; t <= k; t++) {
                // if some of two sets contain less than t elements
                // then we cannot provide this number of swaps
                if (t > A.size() || t > B.size()) break;
                // Swapping t-th maximum of A with t-th minimum of B
                // It means that t-th maximum of A subtracts from suma
                // and t-th minimum of B added to suma
                suma -= A[A.size() - t];
                suma += B[B.size() - t];
                ans = min(ans, suma);
            }
        }
    }
    return ans;
}

优化

让我们假设对于范围[L,R]我们已经知道有序集A和反向有序集B.当我们计算范围[L,R + 1]时,将从B中删除一个元素并插入在A中(这个数字正是值[R + 1])。 C ++有容器集和多集,它允许我们在O(log)时插入和删除并在O(n)时间内迭代。其他编程语言也有相同的容器(在java中是TreeSet / SortedSet)。因此,当我们将R移到R + 1时,我们将对multiset进行一些简单的查询(插入/删除)。

O(N ^ 3)溶液。

int get_minimum_contiguous_sum(vector <int> values, int k) {
    int N = values.size();
    int ans = values[0]; // initializing with any possible sums
    for (int L = 0; L < N; L++) {
        // "inner" multiset
        // Stores in non-increasing order to iterate from beginning
        multiset<int, greater<int> > A;
        // "outer" multiset
        // multiset by defaul stres in non-decreasing order
        multiset<int> B;
        // Initially all elements of array in B
        for (int i = 0; i < N; i++) {
            B.insert(values[i]);
        }
        int suma = 0; // Empty set has sum=0
        for (int R = L; R < N; R++) {// Iterate over all possible R
            // Removing element from B and inserting to A
            B.erase(B.find(values[R]));
            A.insert(values[R]);
            suma += values[R];
            ans = min(ans, suma);
            __typeof(A.begin()) it_a = A.begin();
            __typeof(B.begin()) it_b = B.begin();
            int cur = suma;
            for (int i = 1; i <= k; i++) {
                if (it_a != A.end() && it_b != B.end())
                    break;
                cur -= *it_a;
                cur += *it_b;
                ans = min(ans, cur);
                it_a++;
                it_b++;
            }
        }
    }
    return ans;
}