Reset integer vector

Suppose I have a vector V, natural numbers. If the sum of the integers is greater than the positive integer N, I want to rescale the integers in V so that the sum is & lt = N. Elements from V must remain above zero. The length V is guaranteed to be <= N.

Is there an algorithm to perform this scaling in linear time?

This is not homework, BTW :). I need to rescale a card from characters to character frequencies in order to use range encoding.

Some quick thoughts and googling did not provide a solution to the problem.

EDIT:

Well, the question was somewhat obscure. "Rescale" means "normalize." That is, convert integers to V, for example, by multiplying them by a constant by smaller positive integers, so that the sum criterion (V) & lt = N is met. The better the relationship between the integers is stored, the better the compression.

The problem is open in this way, the method should not look for the optimal (in the sense, for example, the least squares method) a way to preserve the relationship, but "good". Setting the entire vector to 1, as suggested, is unacceptable (if not forced). A “good” would, for example, be to find the smallest divisor (defined below) that satisfies the sum criterion.

The following naive algorithm does not work.

  • Find the current amount (V), Sv
  • divisor: = int (ceil (Sv / N))
  • V , , 1.

v = [1,1,1,10] N = 5.

divisor = ceil(13 / 5) = 3.
V := [1,1,1, max(1, floor(10/3)) = 3]
Sv is now 6 > 5.

[1,1,1,2]

, , - ( ), [1, N], . (Sv/N). , , , len (V) * log (len (V)).

, . - .

+5
4

. GCD .

d = 0
for x in xs:
    d = gcd(d, x)

xs = [x/d for x in xs]

, , N. , , , ( , ).

+4

, 1. , 1 V.length N. , 1 . , , , , , " ". - :

public static void rescale(int[] data, int N) {
    int sum = 0;
    for (int d : data)
        sum += d;

    if (sum > N) {
        int n = N - data.length;
        sum -= data.length;

        for (int a = 0; a < data.length; a++) {
            int toScale = data[a] - 1;
            int scaled = Math.round(toScale * (float) n / sum);

            data[a] = scaled + 1;
            n -= scaled;
            sum -= toScale;
        }
    }
}
+1

:

  • (V), Sv
  • divisor: = int (ceil (Sv/(N - | V | + 1))
  • V ,

v = [1,1,1,10] N = 5:

divisor = ceil (13/2) = 7. V: = [1,1,1, ceil (10/7)) = 2]

+1

This is a "range normalization" problem, but it is very simple. Suppose that S is the sum of the elements of the vector, and S> = N, then S = dN, for some d> = 1. Therefore, d = S / N. Therefore, simply multiply each element of the vector by N / S (i.e., divide by d). The result is a vector with re-scaled components whose sum is N. This procedure is clearly linear :)

0
source

All Articles