算法与数据结构-最小化舍入误差以满足目标
最小化舍入误差以满足目标
题目
leetcode原题:1058. 最小化舍入误差以满足目标
给定一系列价格 [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"
解释:
达到目标是不可能的。
解析
这道题的核心需要思考出:
-
所有数据向上取整的整数和sumFloor-target的相差个数就是 结果中 ceil的个数
-
所有数据向下取整的整数和sumCeil-target的相差个数就是 结果中 floor的个数
已知满足条件的解中的ceil和floor的个数,并且需要求最小误差和,那就分别正序排序floor和ceil的误差list
按照floor和ceil的个数相加得到总和即可!
代码
import java.math.BigDecimal;
class Solution {
public String minimizeError(String[] prices, int target) {
//生成相关待使用数据
List<BigDecimal> floorList = new ArrayList<>(prices.length);
List<BigDecimal> ceilList = new ArrayList<>(prices.length);
int sumFloor = 0;
int sumCeil = 0;
for(String s:prices){
String[] tmps = s.split("\\.");
int i = Integer.parseInt(tmps[0]);
BigDecimal d = new BigDecimal("0."+ tmps[1]);
sumFloor = sumFloor + i;
if(!"000".equals(tmps[1])){
sumCeil = sumCeil + i + 1;
}else{
sumCeil = sumCeil + i;
}
floorList.add(d);
ceilList.add(new BigDecimal("1.000").subtract(d));
}
//判断target是否在sumFloor和sumCeil区间内
if(target < sumFloor || target > sumCeil){
return -1+"";
}
//确定floor和ceil的个数(直接用target-sumFloor计算得到)
//排序舍入误差的两个数组,按照前一步计算得到的个数分别从小到大相加即可
Collections.sort(floorList);
Collections.sort(ceilList);
BigDecimal finalResult = new BigDecimal("0.000");
for(int i = 0;i < target-sumFloor;i++){
finalResult = finalResult.add(ceilList.get(i));
}
for(int i=0;i<prices.length - (target-sumFloor);i++){
finalResult = finalResult.add(floorList.get(i));
}
return finalResult.toString();
}
}