from typing import List
class Solution:
def minimizeError(self, prices: List[str], target: int) -> str:
import math
n = len(prices)
floors = []
ceils = []
total_floor = 0
non_integer_count = 0
diffs = []
for p in prices:
f = math.floor(float(p))
c = math.ceil(float(p))
total_floor += f
if f != c:
non_integer_count += 1
diffs.append(float(p) - f)
floors.append(f)
ceils.append(c)
# To reach target, need to ceil k prices and floor the rest
ceil_count = target - total_floor
if ceil_count < 0 or ceil_count > non_integer_count:
return "-1"
# Sort the fractional parts, smallest first
diffs.sort()
# To minimize error, ceil the ceil_count with largest diffs
error = 0
idx = 0
for p in prices:
f = math.floor(float(p))
c = math.ceil(float(p))
if f == c:
# Already integer
error += 0
else:
# Will decide later
pass
# Ceil ceil_count largest diffs (i.e., smallest fractional parts are floored)
error = 0
sorted_diffs = sorted([float(p) - math.floor(float(p)) for p in prices if math.floor(float(p)) != math.ceil(float(p))])
for i, d in enumerate(sorted_diffs):
if i < len(sorted_diffs) - ceil_count:
error += d
else:
error += 1 - d
return "{0:.3f}".format(error)
#include <vector>
#include <string>
#include <cmath>
#include <algorithm>
#include <iomanip>
#include <sstream>
using namespace std;
class Solution {
public:
string minimizeError(vector<string>& prices, int target) {
int n = prices.size();
int total_floor = 0;
int non_integer_count = 0;
vector<double> diffs;
for (const string& p : prices) {
double val = stod(p);
int f = floor(val);
int c = ceil(val);
total_floor += f;
if (f != c) {
non_integer_count++;
diffs.push_back(val - f);
}
}
int ceil_count = target - total_floor;
if (ceil_count < 0 || ceil_count > non_integer_count) {
return "-1";
}
sort(diffs.begin(), diffs.end());
double error = 0;
for (int i = 0; i < diffs.size(); ++i) {
if (i < (int)diffs.size() - ceil_count) {
error += diffs[i];
} else {
error += 1 - diffs[i];
}
}
stringstream ss;
ss << fixed << setprecision(3) << error;
return ss.str();
}
};
import java.util.*;
class Solution {
public String minimizeError(String[] prices, int target) {
int n = prices.length;
int totalFloor = 0;
int nonIntegerCount = 0;
List<Double> diffs = new ArrayList<>();
for (String p : prices) {
double val = Double.parseDouble(p);
int f = (int)Math.floor(val);
int c = (int)Math.ceil(val);
totalFloor += f;
if (f != c) {
nonIntegerCount++;
diffs.add(val - f);
}
}
int ceilCount = target - totalFloor;
if (ceilCount < 0 || ceilCount > nonIntegerCount) {
return "-1";
}
Collections.sort(diffs);
double error = 0;
for (int i = 0; i < diffs.size(); ++i) {
if (i < diffs.size() - ceilCount) {
error += diffs.get(i);
} else {
error += 1 - diffs.get(i);
}
}
return String.format("%.3f", error);
}
}
/**
* @param {string[]} prices
* @param {number} target
* @return {string}
*/
var minimizeError = function(prices, target) {
let n = prices.length;
let totalFloor = 0;
let nonIntegerCount = 0;
let diffs = [];
for (let p of prices) {
let val = parseFloat(p);
let f = Math.floor(val);
let c = Math.ceil(val);
totalFloor += f;
if (f !== c) {
nonIntegerCount++;
diffs.push(val - f);
}
}
let ceilCount = target - totalFloor;
if (ceilCount < 0 || ceilCount > nonIntegerCount) {
return "-1";
}
diffs.sort((a, b) => a - b);
let error = 0;
for (let i = 0; i < diffs.length; ++i) {
if (i < diffs.length - ceilCount) {
error += diffs[i];
} else {
error += 1 - diffs[i];
}
}
return error.toFixed(3);
};
Given a list of prices as strings prices
, and an integer target
, you must round each price either up (ceil) or down (floor) to an integer. The sum of these rounded values must equal target
. Your task is to minimize the total rounding error, which is the sum of the absolute differences between the original price and its rounded value, across all prices.
If it is impossible to achieve the target
by rounding in this way, return "-1"
. Otherwise, return the minimum total rounding error, formatted with exactly 3 decimal places.
At first, you might think of brute-forcing all possible ways to round each price up or down, checking which combinations sum to the target, and picking the one with the smallest total error. However, this is not feasible for large inputs because the number of combinations grows exponentially with the number of prices.
Instead, let's break down the problem:
This transforms the problem into a selection problem: choose which prices to round up so that the sum matches the target, and do it in a way that minimizes error.
Let's break down the solution step by step:
ceil_count = target - total_floor
. This is the number of non-integer prices that must be rounded up to reach the target.ceil_count
is negative or greater than the number of non-integer prices, it's impossible.fractional part
(if floored) or 1 - fractional part
(if ceiled).ceil_count
prices with the largest fractional parts, and round down the rest.1 - x < x
when x > 0.5
, so it's better to ceil those with large fractions.fractional part
for floored, and 1 - fractional part
for ceiled.
Suppose prices = ["0.700", "2.800", "4.900"]
and target = 8
.
Total floor sum = 0 + 2 + 4 = 6
We must round up 2 of the 3 prices.
Total error = 0.7 + 0.2 + 0.1 = 1.0
Brute-force approach:
The key to this problem is recognizing that for each non-integer price, rounding up or down affects both the sum and the error. By always rounding up the prices with the largest fractional parts (and rounding the rest down), we can guarantee both that the sum matches the target and that the total error is minimized. This greedy approach is both efficient and elegant, reducing the problem to simple sorting and selection.