从总秒数数组的中位数中查找确切的小时数、分钟数、秒数

Finding exact number of hours, minutes, seconds from median of array of total number of seconds

作为整体挑战的一部分,我需要我的代码找到表示总秒数的数字数组(具有偶数或奇数个元素)的中位数,并将该数字转换为包含小时、分钟和总秒数中的秒数。该代码运行良好,但未通过测试,尤其是随机测试。在每种情况下,总秒数都比测试显示少一秒或多一秒。

如何使用当前代码解决这个问题,或者我应该做一些完全不同的事情?

我已经尝试使用不同的数学方法来处理代码,但我仍然遇到秒数比正确答案高或低一秒的问题。

到目前为止,这是我的代码:

concatInt = [ 3432, 4331, 7588, 8432 ]

let rawMedian = function (){

    if(concatInt.length === 0) return 0;

    concatInt.sort(function(a,b){
    return a-b;
    });

    var half = Math.floor(concatInt.length / 2);

    if (concatInt.length % 2)
    return concatInt[half];

    return (concatInt[half - 1] + concatInt[half]) / 2.0;
}

let toStopwatch = function(){
    let hours;
    let minutes;
    let seconds;

    if (rawMedian()/3600 > 1){
    hours = Math.floor(rawMedian()/3600);
    minutes = ((rawMedian() % 3600)/60);
    seconds = Math.floor((minutes - Math.floor(minutes)) * 60);

        if (seconds === 60){
            seconds = seconds -1;
        }

    } else {
    hours = 0;

    if (rawMedian() > 60){
        minutes = (rawMedian()/60);
        seconds = Math.floor((minutes - Math.floor(minutes)) * 60);

        if (seconds === 60){
            seconds = seconds -1;
        }

    } else {
        minutes = 0;
        seconds = rawMedian()
    }
    }

    let timesArr = [];

    timesArr.push(`${hours.toString()}`, `${Math.floor(minutes).toString()}`, `${seconds.toString()}`);
    return timesArr;
}

此代码的结果是 ["1", "39", "19"]。但是,在 Codewars Kata 测试中,上述代码显示不正确,因为秒数比预期秒数多或少一秒。我很乐意根据要求提供我的完整代码和涉及的具体 Kata,但上面的代码显然是导致问题的原因。

有几个问题,但前两个可以解释为什么你会得到一秒的差异:

  • concatInt数组有偶数个值时,中位数会有半秒。你没有说那半秒应该发生什么,但你似乎把它截断了。很可能要求是 round 它。

  • 你计算秒的方式容易出现浮点不精确错误:

    Math.floor((minutes - Math.floor(minutes)) * 60)
    

    例如,如果 minutes 是 8.6,那么这个表达式 - 在应用 Math.floor 之前 - 将导致:35.99999999999998 而不是 36。你应该避免在那里乘以 60。相反,您可以像这样获得秒数:

    median % 60
    
  • 你重复调用rawMedian,这是浪费时间。只需调用一次并将结果存储在变量中以供进一步使用。

  • if (seconds === 60) 条件永远不会发生。该代码可以删除。
  • 您使用的其他 if 构造也不是必需的。中位数是否大于1与计算无关。
  • 小时、分钟和秒应该作为字符串而不是数字返回,这似乎很奇怪。如果确实如此,那么使用模板文字 调用 toString() 方法就太过分了。两种策略中的一种就足够了。

因此,假设中位数应 舍入 ,代码如下所示:

const toStopwatch = function() {
    // Call rawMedian only once.
    // Round it (or if it needs to be truncated, use Math.floor).
    const median = Math.round(rawMedian());
    // Calculation of seconds should just be a modulo 60.
    // No special cases need to be distinguished.
    // Do not cast to strings, unless explicitly required
    return [
        Math.floor(median / 3600),        // hours
        Math.floor((median % 3600) / 60), // minutes
        median % 60                       // seconds
    ];
}