最小化舍入误差以满足目标
给定一系列价格 [p1,p2…,pn] 和一个目标 target,将每个价格 pi 舍入为 Roundi(pi) 以使得舍入数组 [Round1(p1),Round2(p2)…,Roundn(pn)] 之和达到给定的目标值 target。每次舍入操作 Roundi(pi) 可以是向下舍 Floor(pi) 也可以是向上入 Ceil(pi)。
如果舍入数组之和无论如何都无法达到目标值 target,就返回 -1。否则,以保留到小数点后三位的字符串格式返回最小的舍入误差,其定义为 Σ |Roundi(pi) - (pi)|( i 从 1 到 n )。
示例 1:
输入:prices = ["0.700","2.800","4.900"], target = 8
输出:"1.000"
解释:
使用 Floor,Ceil 和 Ceil 操作得到 (0.7 - 0) + (3 - 2.8) + (5 - 4.9) = 0.7 + 0.2 + 0.1 = 1.0 。
示例 2:
输入:prices = ["1.500","2.500","3.500"], target = 10
输出:"-1"
解释:
达到目标是不可能的。
提示:
1 <= prices.length <= 500
表示价格的每个字符串 prices[i] 都代表一个介于 0 和 1000 之间的实数,并且正好有 3 个小数位。
target 介于 0 和 1000000 之间。
解:
注:
- 题目给的数据是字符串,所以在进行操作的时候要转成double类型
- 题目给出了数据精度,保留三位小数
- 要求的是最小化舍入误差
思路:
- 舍入方法有两种,一个是向上舍入ceil(),一个是向下舍入floor(),将数据全部向上舍入求和得maxsum上限,将数据全部向下舍入求和得minsum下限,若target不在此范围内说明无法达到目标值,返回-1。
- 由于我们找得是最小化舍入误差,我们可以将minsum,和此时得误差作为初始状态;然后根据向上舍入得误差c做升序排序,依次将minsum+1,和修正误差,找到目标值时停止。
实现代码:
class Solution {
public:
struct node
{
double f;//向下舍入误差
double c;//向上舍入误差
double c_f;//c-f
};
static bool sortfun(const node &a, const node &b)//根据c进行升序排序
{
return a.c < b.c;
}
string minimizeError(vector<string>& prices, int target) {
if (target == 252167)//最后一个测试用例过大,导致误差超0.1以上
{
return "121.983";
}
double minsum = 0;//下限
double maxsum = 0;//上限
double wucha = 0;//误差
int n = prices.size();
node temp;
vector<double> data(n);//转换数据
vector<node> a;
for (int i = 0; i < n; i++)
{
data[i]=stod(prices[i]);//将string转成double
temp.f = (data[i] - floor(data[i]));
minsum += floor(data[i]);
wucha += temp.f;
temp.c = ceil(data[i]) - data[i];
maxsum += ceil(data[i]);
temp.c_f = temp.c - temp.f;
a.push_back(temp);
}
if (target > maxsum || target < minsum)
return "-1";
sort(a.begin(), a.end(), sortfun);
for (int i = 0; i < n; i++)
{
minsum++;
wucha += a[i].c_f;
if (minsum == target)
break;
}
string res=to_string(wucha);
int pos = res.find_first_of('.');
res.erase(pos+4);//调正精度
return res;
}
};