【问题标题】:Find maximum possible time HH:MM by permuting four given digits通过排列四个给定数字来查找最大可能时间 HH:MM
【发布时间】:2017-06-20 23:24:04
【问题描述】:

我最近参加了一项编码测试,以便在工作中升职。这是我真正努力完成的任务之一,我想知道最好的方法是什么。我使用了大量的 if 和 if else,不是最干净的解决方案,但完成了工作。

我被问到的问题是:

将 4 个数字格式化为 24 小时制时间 (00:00),找出可能的最大(最新)时间,同时考虑到最大小时数为 23,最大分钟数为 59。如果不可能,请返回不可能。

例如:

6、5、2、0 将是 20:56

3、9、5、0 将是 09:53

7、6、3、8 是不可能的

必须返回时间或字符串的示例函数如下所示,A、B、C、D 与上面的逗号分隔列表不同:

function generate(A, B, C, D) {
    // Your code here
} 

人们会如何解决这个问题?

【问题讨论】:

  • 我投票结束这个,因为它太宽泛了。请编辑问题以将其限制为具有足够详细信息的特定问题,以确定适当的答案。请参阅How to Ask 页面以获得澄清此问题的帮助。 SO 不是代码编写服务。你必须展示你到目前为止所做的尝试......
  • 我会蛮力的:生成所有可能的排列,过滤那些有效时间,然后得到最大的。
  • 如果关闭了,发到codegolf.stackexchange.com上吧,我想他们不会对那边的这个问题那么敌视
  • @Malhire85 你应该提出一个挑战,比如运行 100,000 次,看看谁的算法更快。

标签: javascript algorithm


【解决方案1】:

这是我想出的非暴力解决方案。查看代码中的 cmets 以了解它是如何工作的。如果有任何不清楚的地方,我可以帮助澄清。

function generate(A, B, C, D) {
    vals = [A, B, C, D];
    counts = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0];
    for (i = 0; i < vals.length; i++) {
        for (j = vals[i]; j < counts.length; j++) counts[j]++;
    }
    // counts is now populated with the number of values less than or equal to the index it belongs to
    // so counts[2] is the total number of 0's, 1's and 2's
    if (counts[2] === 0) return 'NOT POSSIBLE';
    // if there are no 0's and 1's, then it must start with 2
    mustStartWith2 = counts[1] === 0;
    if (mustStartWith2 && counts[3] === 1) return 'NOT POSSIBLE';
    // We want a count of the number of free digits that are 5 or less (for the minute digit)
    numbersAvailableForMinute = counts[5] - (mustStartWith2 ? 2 : 1); 
    if (numbersAvailableForMinute === 0) return 'NOT POSSIBLE';
    // we now know that it is a valid time
    time = [0, 0, 0, 0];
    // we also know if it starts with 2
    startsWith2 = mustStartWith2 || (numbersAvailableForMinute >= 2 && counts[2] > counts[1]);
    // knowing the starting digit, we know the maximum value for each digit
    maxs = startsWith2 ? [2, 3, 5, 9] : [1, 9, 5, 9];
    for (i = 0; i < maxs.length; i++) {
        // find the first occurrence in counts that has the same count as the maximum
        time[i] = counts.indexOf(counts[maxs[i]]);
        // update counts after the value was removed
        for (j = time[i]; j < counts.length; j++) counts[j]--;
    }
    // create the time
    return time[0]+""+time[1]+":"+time[2]+""+time[3];
}

【讨论】:

  • 10k 调用 15ms,不错!
  • 这确实是一个非常聪明的方法
【解决方案2】:

添加了可执行的sn-p和一些测试用例

function generate(A, B, C, D) {
  var combinations = []
  arguments = Array.from(arguments)
  for (var i = 0; i < 4; i++) {
    for (var j = 0; j < 4; j++) {
      if (i !== j) {
        var num = +(arguments[i] + '' + arguments[j])
        if (num <= 59 && combinations.indexOf(num) === -1)
          combinations.push(num)
      }
    }
  }
  combinations.sort((a, b) => a - b);
  var hours = combinations.filter(hour => hour <= 23);

  for (var i = hours.length - 1; i >= 0; i--) {
    for (var j = combinations.length - 1; j >= 0; j--) {
      if (computeMax(hours[i], combinations[j], arguments))
        return hours[i] + ':' + combinations[j]
    }
  }
  return 'not possible'
}

function computeMax(maxHour, maxMinute, args) {
  var minute = String(maxMinute)
  var hour = String(maxHour)
  for (var k = 0; k < minute.length; k++)
    if (hour.indexOf(minute[k]) > -1 && args.indexOf(+minute[k]) === args.lastIndexOf(+minute[k]))
      return false
  return true
}
console.log('generate(1,7,2,7)', generate(1,7,2,7))
console.log('generate(6,5,2,0)', generate(6,5,2,0))
console.log('generate(3,9,5,0)', generate(3,9,5,0))
console.log('generate(7,6,3,8)', generate(7,6,3,8))
console.log('generate(0,1,2,3)', generate(0,1,2,3))
console.log('generate(1,1,1,2)', generate(1,1,1,2))
console.log('generate(1,1,1,1)', generate(1,1,1,1))
console.log('generate(5,6,7,8)', generate(5,6,7,8))
console.log('generate(2,9,3,1)', generate(2,9,3,1))

【讨论】:

  • @Dummy 22:27 是出色的输出......但对于另一个输入。请注意,第二个和第三个示例也会产生错误的答案(它们重复使用数字)
  • 我几乎很失望地说这个,因为这是一个非常聪明的尝试,但是 generate(1,1,1,2) 返回 21:12。
  • 您应该检查i!==j 而不是arguments[i] !== arguments[j] 对吗?但即便如此,这也会失败,因为它不会检查输出的小时和分钟是否重叠......
  • @DanielBeck 现在怎么样?
  • @DanielBeck 我们,程序员,当我们无法解决某事并总是试图找到解决它的方法时,难道我们不觉得很痒吗?
【解决方案3】:

一种使用预先计算的字符串的方法,包含所有可能的排列。

function generate(A,B,C,D){
  var isValidTime = /^(?:[01]\d|2[0-3]):(?:[0-5]\d)$/;
  var pattern = "0123012 0132013 0213021 0231023 0312031 0321032".replace(/\d/g, i => arguments[+i]);
  var max = "";
  for(var i=pattern.length-4; i--; ){
    var time = pattern.substr(i,2) + ":" + pattern.substr(i+2,2);
    if(time > max && isValidTime.test(time)) 
      max = time;
  }
  return max || "NOT POSSIBLE";
}

[
  [6,5,0,2],
  [3,9,5,0],
  [7,6,3,8]
].forEach(arr => console.log(arr + ' -> ' + generate(...arr)));
.as-console-wrapper{top:0;max-height:100%!important}

但我们可以改进这一点,通过使用正则表达式仅查找有效时间:

function generate(A,B,C,D){	
  var pattern = "0123012 0132013 0213021 0231023 0312031 0321032".replace(/\d/g, i => arguments[+i]);
  console.log(pattern);
  var matchValidTime = /([01]\d|2[0-3])([0-5]\d)/g, m, max = "";
  while(m = matchValidTime.exec(pattern)){
    var time = m[1] + ":" + m[2];
    if(time > max) max = time;
    console.log("index: %o  time: %o  max: %o", m.index, time, max);
    matchValidTime.lastIndex = m.index+1; //to find intersecting matches
  }
  return max || "NOT POSSIBLE";
}

   [
  [1,2,3,4],
  //[6,5,0,2],
  //[3,9,5,0],
  //[7,6,3,8]
].forEach(arr => console.log(arr + ' -> ' + generate(...arr)));
.as-console-wrapper{top:0;max-height:100%!important}

【讨论】:

    【解决方案4】:

    当我了解到您可以将问题视为“生成小于 24 的数字和小于 60 的数字”而不是尝试使用单个数字时,对此的推理变得容易得多。

    这会遍历集合中的数字对,找到可以从这对数字中得出的最大有效小时,然后找到可以从剩余数字中得出的最大有效分钟。

    var generate = function(a, b, c, d) {
      var biggest = function(a, b, max) {
        // returns largest of 'ab' or 'ba' which is below max, or false.
        // I'm sure there's a more concise way to do this, but:
        var x = '' + a + b;
        var y = '' + b + a;
        if (max > x && max > y) {
          var tmp = Math.max(x,y);
          return (tmp < 10) ? "0"+tmp : tmp;
        }
        if (max > x) return x;
        if (max > y) return y;
        return false;
      }
    
      var output = false;
    
      var input = [].slice.call(arguments);
      for (var i = 0; i < arguments.length; i++) {
        for (var j = i + 1; j < arguments.length; j++) {
          // for every pair of numbers in the input:
          var hour = biggest(input[i], input[j], 24); // What's the biggest valid hour we can make of that pair?
          if (hour) {
            // do the leftovers make a valid minute?
            var tmp = input.slice(); // copy the input
            tmp.splice(j, 1);
            tmp.splice(i, 1);
            var minute = biggest(tmp[0], tmp[1], 60);
            if (hour && minute) {
              // keep this one if it's bigger than what we had before:
              var nval = hour + ':' + minute;
              if (!output || nval > output) output = nval;
            }
          }
        }
      }
      return output || 'NOT POSSIBLE';
    }
    
    /* --------------- Start correctness test --------------------- */
      var tests = ['0000', '1212', '1234', '2359', '2360','2362','2366', '1415', '1112', '1277', '9999', '0101'];
    console.log('---');
    for (var i = 0; i < tests.length; i++) {
      console.log(
        tests[i],
        generate.apply(this, tests[i].split(''))
      )
    }
    
    
    
    /* --------------- Start Speed Test --------------------- */
    
    let startTime = Math.floor(Date.now());
    let times = 10000; //how many generate call you want?
    let timesHolder = times;
    
    while (times--) {
      let A = randNum();
      let B = randNum();
      let C = randNum();
      let D = randNum();
      generate(A, B, C, D);
      if (times == 0) {
        let totalTime = Math.floor(Date.now()) - startTime;
        let msg = timesHolder + ' Call Finished Within -> ' + totalTime + ' ms <-';
        console.log(msg);
        // alert(msg);
      }
    }
    
    function randNum() {
      return Math.floor(Math.random() * (9 - 0 + 1)) + 0;
    }
    
    /* --------------- END Speed Test --------------------- */

    【讨论】:

    • 我已经开始检查至少一个数字
    • 或多或少我做了什么。
    • 如果你有输入(2、7、1、7),你的算法会失败吗?因为你会选择 w=2,x = 1,然后剩下 7 和 7。真正的解决方案是 17:27。
    • 10000 调用在 -> 74 毫秒内完成
    • 无论如何都不是最快的,但我可以接受 :)
    【解决方案5】:

    想法:

    • 查找所有组合数组(共 24 个)
    • 过滤掉所有无效组合(时间格式)
    • 寻找时间价值
    • 输出具有最大时间值的数组

    解决方案:

    第一个allCom将返回4个数字的所有组合(共24个组合)

    然后对于 24 个数组(组合)调用 .forEach 遍历每个数组,检查它是否是有效的时间格式。如果它是有效的时间格式,则使用

    计算时间值

    如果时间是 AB:CD 那么值:

    A = A * 10 小时 = A * 10 * 3600s = A * 36000s

    B = B * 1 小时 = B * 3600 秒

    C = C * 10s

    D = D

    总值 = A*36000 + B*3600 + C*10 + D

    现在你得到了当前数组的值,与保存的Max比较,如果这个值更大,则替换最大值。

    在循环结束时确定是否找到最大值或它无效。

    generate(6, 5, 2, 0);
    generate(3, 9, 5, 0);
    generate(7, 6, 3, 8);
    generate(1, 7, 2, 7);
    generate(1, 1, 1, 2);
    
    // return all combination of 4 number (24 combination total)
    function allCom(inputArray) {
      var result = inputArray.reduce(function permute(res, item, key, arr) {
        return res.concat(arr.length > 1 && arr.slice(0, key).concat(arr.slice(key + 1)).reduce(permute, []).map(function(perm) {
          return [item].concat(perm);
        }) || item);
      }, []);
      return result;
    }
    
    // core function to determine the max comb
    function generate(A, B, C, D) {
      let input = [A, B, C, D];
      let allComb = allCom(input);
      let max = '';
      let maxA = [];
    
      allComb.forEach(function(comb, index, arr) {
        if (validCom(comb)) {
          let temp = calValue(comb);
          maxA = temp > max ? comb : maxA;
          max = temp > max ? temp : max;
        }
        if (index == allComb.length - 1) {
          if (max) {
            return console.log('For ' + JSON.stringify(input) + ' found max comb: ' + maxA[0] + maxA[1] + ':' + maxA[2] + maxA[3]);
          }
          return console.log('Sorry ' + JSON.stringify(input) + ' is not valid');
        }
      });
    }
    
    // check if this array is valid time format, ex [1,2,9,0] false, [2,2,5,5] true
    function validCom(ar) {
      if (ar[0] <= 2 && ((ar[0] == 2 && ar[1] < 4) || (ar[0] != 2 && ar[1] <= 9)) && ar[2] <= 5 && ar[3] <= 9) {
        return true;
      }
      return false;
    }
    
    // calculate the total value of this comb array
    function calValue(ar) {
      return +ar[0] * 36000 + +ar[1] * 3600 + +ar[2] * 10 + +ar[0];
    }
    
    
    $('button').on('click', function(e) {
        let inp = $('select');
        generate(inp[0].value, inp[1].value, inp[2].value, inp[3].value);
    });
    
    
    var s = $('<select />');
    for(i=0;i<10;i++) {
        $('<option />', {value: i, text: i}).appendTo(s);
    }
    s.clone().appendTo('#myform');
    s.clone().appendTo('#myform');
    s.clone().appendTo('#myform');
    s.clone().appendTo('#myform');
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
    <form id="myform">
    </form>
    <br>
    <button type="button">Submit</button>

    我还邀请人们放这段代码来测试他们算法的运行速度。 (使用@Diego ZoracKy 的一些代码来制作这个,谢谢!)。玩得开心!!!

    /* --------------- Start Speed Test --------------------- */
    let startTime = Math.floor(Date.now());
    let times = 10000; //how many generate call you want?
    let timesHolder = times;
    
    while (times--) {
      let A = randNum();
      let B = randNum();
      let C = randNum();
      let D = randNum();
      generate(A, B, C, D);
      if (times == 0) {
        let totalTime = Math.floor(Date.now()) - startTime;
        let msg = timesHolder + ' Call Finished Within -> ' + totalTime + ' ms <-';
        console.log(msg);
        alert(msg);
      }
    }
    
    function randNum() {
      return Math.floor(Math.random() * (9 - 0 + 1)) + 0;
    }
    /* --------------- END Speed Test --------------------- */
    

    /* --------------- Start Speed Test --------------------- */
    let startTime = Math.floor(Date.now());
    let times = 10000; //how many generate call you want?
    let timesHolder = times;
    
    while (times--) {
      let A = randNum();
      let B = randNum();
      let C = randNum();
      let D = randNum();
      generate(A, B, C, D);
      if (times == 0) {
        let totalTime = Math.floor(Date.now()) - startTime;
        let msg = timesHolder + ' Call Finished Within -> ' + totalTime + ' ms <-';
        console.log(msg);
        alert(msg);
      }
    }
    
    function randNum() {
      return Math.floor(Math.random() * (9 - 0 + 1)) + 0;
    }
    /* --------------- END Speed Test --------------------- */
    
    // return all combination of 4 number (24 combination total)
    function allCom(inputArray) {
      var result = inputArray.reduce(function permute(res, item, key, arr) {
        return res.concat(arr.length > 1 && arr.slice(0, key).concat(arr.slice(key + 1)).reduce(permute, []).map(function(perm) {
          return [item].concat(perm);
        }) || item);
      }, []);
      return result;
    }
    
    // core function to determine the max comb
    function generate(A, B, C, D) {
      let input = [A, B, C, D];
      let allComb = allCom(input);
      let max = '';
      let maxA = [];
    
      allComb.forEach(function(comb, index, arr) {
        if (validCom(comb)) {
          let temp = calValue(comb);
          maxA = temp > max ? comb : maxA;
          max = temp > max ? temp : max;
        }
        if (index == allComb.length - 1) {
          if (max) {
            return 'For ' + JSON.stringify(input) + ' found max comb: ' + maxA[0] + maxA[1] + ':' + maxA[2] + maxA[3];
          }
          return 'Sorry ' + JSON.stringify(input) + ' is not valid';
        }
      });
    }
    
    // check if this array is valid time format, ex [1,2,9,0] false, [2,2,5,5] true
    function validCom(ar) {
      if (ar[0] <= 2 && ((ar[0] == 2 && ar[1] < 4) || (ar[0] != 2 && ar[1] <= 9)) && ar[2] <= 5 && ar[3] <= 9) {
        return true;
      }
      return false;
    }
    
    // calculate the total value of this comb array
    function calValue(ar) {
      return +ar[0] * 36000 + +ar[1] * 3600 + +ar[2] * 10 + +ar[0];
    }

    【讨论】:

    • 你用 jQuery 做什么?
    • 0,3,5,9 可以产生时间09:53
    • 这个也失败了generate(1,7,2,7);。我认为@CameronAavik 是这个难题的真正赢家,因为它成功地找到了最狡猾的输入
    • 嘿。我会听从@cameronAavik,我现在只是在观望 :)
    【解决方案6】:
    from itertools  import permutations
    class Solution(object):
        def largestTimeFromDigits(self, A):
            arr = []
            for i in permutations(A,4):
                if int(str(i[0])+str(i[1])) < 24 and int(str(i[2])+ str(i[3])) < 60:
                    arr.append(list(i))
            
            if arr:
                cnt = arr[0]
                for t in arr[1:]:
                    if int(str(t[0])+str(t[1])) > int(str(cnt[0])+ str(cnt[1])):
                        cnt = t
                    elif int(str(t[0])+str(t[1])) == int(str(cnt[0])+ str(cnt[1])):
                        if int(str(t[2])+str(t[3])) > int(str(cnt[2])+ str(cnt[3])):
                            cnt = t
                return str(cnt[0])+ str(cnt[1]) + ":" + str(cnt[2])+ str(cnt[3])  
            else:
                return ""
    

    【讨论】:

    • 嘿@navneet-kumar,欢迎来到 Stack Overflow!我想问你是否可以进一步说明你的代码是如何工作的。您可以...吗?提前谢谢!
    • 这看起来不像 javascript。
    【解决方案7】:

    我会使用 JavaScript 的 Date 对象来确定特定时间是否有效,方法是将字符串解析为 ISO 日期时间字符串(如 1970-01-01T62:87),然后测试 !isNaN( aDateInstance.getTime() ) 并将 Date 实例与之前保存的最大Date 实例(如果适用):

    // permutator() borrowed from https://stackoverflow.com/a/20871714
    function permutator( inputArr ) {
      var results = [];
    
      function permute( arr, memo ) {
        var cur, memo = memo || [];
    
        for( var i = 0; i < arr.length; i++ ) {
          cur = arr.splice( i, 1 );
          if( arr.length === 0 ) {
            results.push( memo.concat( cur ) );
          }
          permute( arr.slice(), memo.concat( cur ) );
          arr.splice( i, 0, cur[ 0 ] );
        }
    
        return results;
      }
    
      return permute( inputArr );
    }
    
    function generate( A, B, C, D ) {
      var r = null;
      permutator( [ A, B, C, D ] ).forEach( function( p ) {
        var d = new Date( '1970-01-01T' + p[ 0 ] + '' + p[ 1 ] + ':' + p[ 2 ] + '' + p[ 3 ] );
        if( !isNaN( d.getTime() ) && d > r ) {
          r = d;
        }
      } );
    
      var h, m;
      return r ? ( ( h = r.getHours() ) < 10 ? '0' + h : h ) + ':' + ( ( m = r.getMinutes() ) < 10 ? '0' + m : m ) : 'NOT POSSIBLE';
    }
    

    【讨论】:

    • 10k 调用 450ms =D
    【解决方案8】:

    这就是我想出的。几乎没有优雅,我可能会尝试整理它以使其更有效率。我有一种感觉,蛮力方法将是最干净、最有效的方法。这是一团糟。

    // w: highest value 2 or less
    // UNLESS: 1 of b, c, or d are less than 3 while the other two are greater than 7
    // x: highest value
    // UNLESS: last was 2 then highest value less than 2
    // y: highest value less than 5
    // z: highest remaining value
    
    function findhighestwhere(array, condition) {
      let res = null
      let val = -1
      let i = 0
      for (let x of array) {
        if (x !== null && condition(x) && x > val) {
          res = i
          val = x
        }
        i++
      }
      // console.log(`Test index: ${res} \n Test value: ${val}`)
      return res
    }
    
    function generate(a,b,c,d) {
      // console.log(`Testing: ${a}${b}${c}${d}`)
      let array = [a,b,c,d]
      let wi = findhighestwhere(array, x => x <= 2)
      // That one pain in the conditional edge-case
      if ( array[wi] == 2 ) {
        // console.log(`Encountered First Position 2 Checking for Edge Case`)
        let i = 0
        let lowcount = 0
        let highcount = 0
        for (let x of array) {
          if ( i != wi && x <= 3 ) lowcount++
          if ( i != wi && x >= 6 ) highcount++
          i++
        }
        if ( lowcount == 1 && highcount == 2 ) {
          // console.log(`Edge Case Encountered`)
          wi = findhighestwhere(array, x => x <= 1)
        }
      }
      if ( wi === null ) return false
      let w = array[wi]
      // console.log(`W: ${w}`)
      array[wi] = null  
      if ( w == 2 ) {
        var xi = findhighestwhere(array, x => x <= 3)
      } else {
        var xi = findhighestwhere(array, x => true)
      }
      if ( xi === null ) return false
      let x = array[xi]
      // console.log(`X: ${x}`)
      array[xi] = null
      let yi = findhighestwhere(array, x => x <= 5)
      if ( yi === null ) return false
      let y = array[yi]
      // console.log(`Y: ${y}`)
      array[yi] = null
      let zi = findhighestwhere(array, x => true)
      if ( zi === null ) return false
      let z = array[zi]
      // console.log(`Z: ${z}`)
      array[zi] = null
    
      return `${w}${x}:${y}${z}`
    }
    
    
    console.log(`6520: ${generate(6,5,2,0)}`) // 6520: 20:56
    console.log(`3950: ${generate(3,9,5,0)}`) // 3950: 09:53
    console.log(`7638: ${generate(7,6,3,8)}`) // 7638: false
    console.log(`1727: ${generate(1,7,2,7)}`) // 1727: 17:27
    

    【讨论】:

    • 我有一种感觉,我可以通过将 w 的边缘情况推入被传递给 findhighestwhere 的匿名函数来使它更整洁一些,但我将离开机器大约 18 小时.
    【解决方案9】:

    function pickN(arr, clause){
    	const index = arr.findIndex(clause);
    	if(index >= 0){
    		return arr.splice(index, 1)[0];
    	}
    }
    
    function getMaxTime(args, tryN1 = 2){
    	let paramsArray = Array.from(args).sort((a , b) => a < b);
    
    	let n1 = pickN(paramsArray, n => n <= tryN1);
    	let n2 = pickN(paramsArray, n => n1 === 2 ? n <= 3 : n);
    	let n3 = pickN(paramsArray, n => n <= 5);
    	let n4 = paramsArray.pop();
    
    	if([n1,n2,n3,n4].some(n => typeof(n) === `undefined`)){
    		return tryN1 > 0 && getMaxTime(args, --tryN1);
    	}
    
    	return `${n1}${n2}:${n3}${n4}`;
    }
    
    function generate(A, B, C, D) {
    	let maxTime = getMaxTime(arguments);
    	if(maxTime){
    		return maxTime;
    	}
    
    	return `NOT POSSIBLE`;
    }
    
    
    ////////////////////////
    // TESTING MANY TIMES //
    ////////////////////////
    let times = 100;
    while(times--){
    	let paramA = randomNumbers();
    	let paramB = randomNumbers();
    	let paramC = randomNumbers();
    	let paramD = randomNumbers();
    	let result = generate(paramA, paramB, paramC, paramD);
    
    	console.log(`${paramA},${paramB},${paramC},${paramD} = ${result}`);
    }
    
    function randomNumbers(){
    	return Math.floor(Math.random() * (9 - 0 + 1)) + 0;
    }

    【讨论】:

    • 对于 0,0,2,9,您的代码给出 09:20,但正确答案是 20:09。
    • @MichaelLiu 谢谢。我发现了另一个错误。我发布了一个带有修复的编辑,但我对它的冗长还不满意。
    • 我认为 sort() 不起作用—— generate(1,2,7,7) 失败但 generate(1,7,7,2) 成功。这是一个非常困难的难题,无需蛮力即可解决!
    • @DanielBeck 告诉我,也只有 50 分钟的时间来完成
    • 10k 调用 70ms =D
    【解决方案10】:

    对于地点,AB:CD

    If at any point a condition cannot be fulfilled:
      return NOT POSSIBLE
    
    If there are two numbers greater than 5:
      place the larger in B, smaller in D
    
    for non-filled places from left to right:
      if B > 3:
        place a 1 in A
      else:
        place the largest number smaller than 3 in A
    
      if A is 2:
        place the largest number smaller than 4 in B
      else:
        place the largest number in B
    
      place the largest number smaller than 6 in C
      place the remaining number in D
    

    【讨论】:

      【解决方案11】:

      我可以处理大量的ifs 和elses,但我很确定这已经完成了。相反,我采用不同的方式。

      • 我们得到给定 4 个数字的所有排列。这里我使用我的 rotationPerm 算法。我猜是one of the fastest ever in JS
      • 过滤掉无效时间
      • 从其余值中选择最大的值
      • 格式为时间。

      function getMaxTime(...a){
        
        function perm(a){
          var r = [[a[0]]],
              t = [],
              s = [];
          if (a.length <= 1) return a;
          for (var i = 1, la = a.length; i < la; i++){
            for (var j = 0, lr = r.length; j < lr; j++){
              r[j].push(a[i]);
              t.push(r[j]);
              for(var k = 1, lrj = r[j].length; k < lrj; k++){
                for (var l = 0; l < lrj; l++) s[l] = r[j][(k+l)%lrj];
                t[t.length] = s;
                s = [];
              }
            }
            r = t;
            t = [];
          }
          return r;
        }
        
        function isValidTime(a){
          return 10*a[0]+a[1] < 24 && 10*a[2]+a[3] < 60;
        }
        
        var time = perm(a).filter(t => isValidTime(t))         // filter out the invalids
                          .map(t => t.reduce((p,c) => 10*p+c)) // convert them into 4 digit integer
                          .reduce((p,c) => p > c ? p : c, -1); // get the biggest
        return time >= 0 ? ("0" + ~~(time/100)).slice(-2) + ":" + time%100 : "No way..!";
      }
      console.log(getMaxTime(6, 5, 2, 0));
      console.log(getMaxTime(3, 9, 5, 0));
      console.log(getMaxTime(7, 6, 3, 8));

      【讨论】:

      • 10k 调用 65ms =D
      • @Daniel H 你检查过其他人了吗?如果将Math.max(...array) 部分替换为array.reduce((p,c) =&gt; p &gt; c ? p : c, -1);,可能会变得更快。让我改变...
      • 是的,我的小脚本只检查速度,不检查正确性。最快的是 15-20 毫秒左右,我的真的很慢,比如 600 毫秒哈哈
      • @Daniel H 感谢您提供的信息。与命令式代码不同,数组方法主要是性能负担,但它们使其清晰而美观。
      【解决方案12】:

      更新

      只是想办法提高性能,这个新想法的灵感来自于计数排序。

      只需计算每个数字的个数,然后根据以下依赖链,粗略地找到最佳可能性。答案将是其中之一,优先级最高:

      1. 2[最大位数
      2. 1[*]:[最大位数
      3. 0[*]:[最大位数

      /* --------------- Start Speed Test --------------------- */
        var startTime = Math.floor(Date.now());
        var times = 10000; //how many generate call you want?
        var timesHolder = times;
      
        while (times--) {
          var A = randNum();
          var B = randNum();
          var C = randNum();
          var D = randNum();
          generate(A, B, C, D);
          if (times == 0) {
            var totalTime = Math.floor(Date.now()) - startTime;
            var msg = timesHolder + ' Call Finished Within -> ' + totalTime + ' ms <-';
            console.log(msg);
            alert(msg);
          }
        }
      
        function randNum() {
          return Math.floor(Math.random() * (9 - 0 + 1)) + 0;
        }
        /* --------------- END Speed Test --------------------- */
        
        function generate(A,B,C,D){
            var cnt = [0,0,0,0,0,0,0,0,0,0], ans = ['', ''];      
            cnt[A]++; cnt[B]++; cnt[C]++; cnt[D]++;
            
            function gen(part, max){
               for(var i=max; i>=0; i--) if(cnt[i]){
                    ans[part] += i;
                    cnt[i]--;
                    return 1;
                }
                return 0;
            }
            function rollback(first){
                cnt[first]++;
                for(var i in ans[0]) cnt[ans[0][i]]++;
                for(var i in ans[1]) cnt[ans[1][i]]++;
                ans[0] = ans[1] = '';
            }
            /*** Main logic, based on the chain of dependencies ***/
            if(cnt[2]){
                cnt[2]--;
                if(!gen(0, 3) || !gen(1,5) || !gen(1,9)) rollback(2);
                else return '2' + ans[0] + ':' + ans[1];
            }
            if(cnt[1]){
                cnt[1]--;
                if(!gen(0, 9) || !gen(1,5) || !gen(1,9)) rollback(1);
                else return '1' + ans[0] + ':' + ans[1];
            }
            if(cnt[0]){
                cnt[0]--;
                if(!gen(0, 9) || !gen(1,5) || !gen(1,9)) rollback(0);
                else return '0' + ans[0] + ':' + ans[1];
            }
            return 'NOT POSSIBLE';
        }
        console.log(generate(1,7,2,7));
        console.log(generate(0,0,2,9));
        console.log(generate(6,5,2,0));
        console.log(generate(3,9,5,0));
        console.log(generate(7,6,3,8));
        console.log(generate(0,0,0,0));
        console.log(generate(9,9,9,9));
        console.log(generate(1,2,3,4));

      【讨论】:

      • 10k 调用 28ms =D
      • @DanielH 我用一个新想法重写了代码..希望它现在运行得更好:P
      【解决方案13】:

      这是我的尝试。添加了带有解释的内联 cmets。

      // think of the result of the form {h1}{h2}:{ms}
      function generate(a, b, c, d) {
        const digits = [a, b, c, d];
      
        // extract possible starting digits
        const possibleH1s = [2, 1, 0].filter(digit => digits.includes(digit));
        
        // check result, starting from the highest possible h1 digit
        // if digits doesn't contains any of [2,1,0], we're done
        for (const h1 of possibleH1s) {
      
          // extract the remaining digits after h1
          const withoutH1 = removeFrom(digits, h1);
          
          // determine all possible h2 digits based on the h1 digit
          const possibleH2s = h1 === 2
            ? [3,2,1,0]
            : [9,8,7,6,5,4,3,2,1,0];
      
          // find the highest possible h2 digit (works because array of possible digits above is in descending order)
          // if none exist, loop iteration is done
          const h2 = possibleH2s.find(d => withoutH1.includes(d));
          if (typeof h2 !== 'number') {
            continue;
          }
          
          // remove h2 so we can search for the remaining ms digits
          const [possibleMS1, possibleMS2] = removeFrom(withoutH1, h2);
          
          // build the two possible combinations for ms    
          const possibleMs = [
            Number(`${possibleMS1}${possibleMS2}`),
            Number(`${possibleMS2}${possibleMS1}`)
          ];
          
          // determine the min and max ms value
          const maxMs = Math.max(...possibleMs);
          const minMs = Math.min(...possibleMs);
      
          // find the largest valid ms value
          // if none exist, loop iteration is done
          const ms = maxMs < 60 ? maxMs : minMs < 60 ? minMs : undefined;
          if (typeof ms !== 'number') {
            continue;
          }
      
          // yay, time
          return `${h1}${h2}:${padWithZero(ms)}`;
        }
        
        return 'NOT POSSIBLE';
      }
      
      // returns a new array by removing a single element 
      // that is equal to `val` from the given array
      // (performs better than splice cause if doesn't do array shift)
      function removeFrom(arr, val) {
        const newArr = [];
        for (let i = 0, l = arr.length, found = false; i < l; i++) {
          if (arr[i] !== val || found) {
            newArr.push(arr[i]);
          } else {
            found = true;
          }
        }
        return newArr;
      }
      
      function padWithZero(digit) {
        return digit < 10 ? `0${digit}` : `${digit}`;
      }
      
      /* --------------- Tests --------------------- */
      
      const speedTest = (times = 10000) => {
        let counter = times;
        const start = performance.now();
        while (counter--) {
          const A = randNum();
          const B = randNum();
          const C = randNum();
          const D = randNum();
          generate(A, B, C, D);
          if (counter == 0) {
            const ms = performance.now() - start;
            console.log(`${times} times to run generate took ${ms} ms`);
          }
        }
      }
      
      const randNum = () => Math.floor(Math.random() * (9 - 0 + 1)) + 0;
      
      const accuracyTest = () => {
        console.assert(generate(1,7,2,7) === '17:27');
        console.assert(generate(0,0,2,9) === '20:09');
        console.assert(generate(6,5,2,0) === '20:56');
        console.assert(generate(3,9,5,0) === '09:53');
        console.assert(generate(7,6,3,8) === 'NOT POSSIBLE');
        console.assert(generate(0,0,0,0) === '00:00');
        console.assert(generate(9,9,9,9) === 'NOT POSSIBLE');
        console.assert(generate(1,2,3,4) === '23:41');
        console.log('All good!');
      }
      
      speedTest();
      accuracyTest();

      【讨论】:

        【解决方案14】:

        我认为这种方法称为蛮力。从@Dummy 的回答中抽取测试样本。

        <script>
        function generate(A, B, C, D) {
            var result = -1
            var v = [A, B, C, D]
            for (i = 0; i < 4; i++) {
                for (j = 0; j < 4; j++) if (j != i) {
                    for (k = 0; k < 4; k++) if (k != j && k != i) {
                        for (m = 0; m < 4; m++) if (m != k && m != j && m != i) {
                            if (v[i]*10 + v[j] < 24 && v[k]*10 + v[m] < 60) { //legal time
                                if (v[i]*1000 + v[j]*100 + v[k]*10 + v[m] > result) {
                                    result = v[i]*1000 + v[j]*100 + v[k]*10 + v[m]
                                }
                            }
                        }
                    }
                }
            }
            return result >= 0? Math.floor(result/100) + ':' + result%100: 'NOT POSSIBLE'
        } 
        
        console.log('generate(1,7,2,7)', generate(1,7,2,7))
        console.log('generate(6,5,2,0)', generate(6,5,2,0))
        console.log('generate(3,9,5,0)', generate(3,9,5,0))
        console.log('generate(7,6,3,8)', generate(7,6,3,8))
        console.log('generate(0,1,2,3)', generate(0,1,2,3))
        console.log('generate(1,1,1,2)', generate(1,1,1,2))
        console.log('generate(1,1,1,1)', generate(1,1,1,1))
        console.log('generate(5,6,7,8)', generate(5,6,7,8))
        console.log('generate(2,9,3,1)', generate(2,9,3,1))
        </script>
        

        【讨论】:

          【解决方案15】:

          嗯,从this suggestion about permutations in JavaScript 开始,其中,给定一组值得到所有可能的唯一排列,我得到了这个解决方案:

          • 假设您拥有所有可能的 4 位数字组合,
          • 并假设正确的小时值在 00-23 范围内
          • 并假设正确的分钟值在 00-59 范围内

          您可以使用这个简单的代码来执行操作:

          function maxTime(a, b, c, d) {
            var ps = Array.from(uniquePermutations([a, b, c, d]));
            while (maxHour = ps.pop()) {
              var timing = maxHour.join('').replace(/([0-9]{2})([0-9]{2})/, '$1:$2');
          
              if (/([0-1][0-9]|2[0-3])\:[0-5][0-9]/.test(timing)) {
                return timing;
              }
            }
            return false;
          }
          

          function swap(a, i, j) {
            const t = a[i];
            a[i] = a[j];
            a[j] = t;
          }
          
          function reverseSuffix(a, start) {
            if (start === 0) {
              a.reverse();
            } else {
              let left = start;
              let right = a.length - 1;
          
              while (left < right)
                swap(a, left++, right--);
            }
          }
          
          function nextPermutation(a) {
            // 1. find the largest index `i` such that a[i] < a[i + 1].
            // 2. find the largest `j` (> i) such that a[i] < a[j].
            // 3. swap a[i] with a[j].
            // 4. reverse the suffix of `a` starting at index (i + 1).
            //
            // For a more intuitive description of this algorithm, see:
            //   https://www.nayuki.io/page/next-lexicographical-permutation-algorithm
            const reversedIndices = [...Array(a.length).keys()].reverse();
          
            // Step #1; (note: `.slice(1)` maybe not necessary in JS?)
            const i = reversedIndices.slice(1).find(i => a[i] < a[i + 1]);
          
            if (i === undefined) {
              a.reverse();
              return false;
            }
          
            // Steps #2-4
            const j = reversedIndices.find(j => a[i] < a[j]);
            swap(a, i, j);
            reverseSuffix(a, i + 1);
            return true;
          }
          
          function* uniquePermutations(a) {
            const b = a.slice().sort();
          
            do {
              yield b.slice();
            } while (nextPermutation(b));
          }
          
          
          function maxTime(a, b, c, d) {
            var ps = Array.from(uniquePermutations([a, b, c, d]));
            while (maxHour = ps.pop()) {
              var timing = maxHour.join('').replace(/([0-9]{2})([0-9]{2})/, '$1:$2');
          
              if (/([0-1][0-9]|2[0-3])\:[0-5][0-9]/.test(timing)) {
                return timing;
          
              }
            }
            return false;
          }
          console.log(maxTime(6, 5, 2, 0));
          console.log(maxTime(3, 9, 5, 0));
          console.log(maxTime(7, 6, 3, 8));

          【讨论】:

            【解决方案16】:

            嗯.....我想如果你把它分解成更简单的问题真的很简单:例如找到所有有效时间(00-23),对于这些有效时间中的每一个,使用剩余的数字来找到有效分钟(00- 59)、组合和排序。在伪代码中类似于以下内容

                valid_times = []
                function get_max(digits[]) {
                            for each d1 in digits[]
                        for each d2 in (digits[] except d1)
                            res = is_valid_hour(d1, d2)
                            if(res > 0) {
                                if(res == 2)
                                    swap(d1, d2)
                                d3 = one of the rest in (digits except d1 and d2)
                                d4 = digit left in digits[]
                                res = is_valid_minute(d3, d4)
                                if(res > 0)
                                    if(res == 2)
                                        swap(d3, d4)
                                    add (d1, d2, d3, d4) to valid_times;
                            }
                    sort(valid_times)
                    print valid_times[0]
                }
            
                function is_valid_hour(a, b) {
                    if (a*10+b<24)
                        return 1
            
                    if (b*10+a<24)
                        return 2
            
                    return 0;
                }
            
                function is_valid_minute(a, b) {
                    if (a*10+b<60)
                        return 1
            
                    if (b*10+a<60)
                        return 2
            
                    return 0;
                }
            

            【讨论】:

              【解决方案17】:

              它既不优雅也不漂亮,但它似乎可以解决问题!

              const NOT_POSSIBLE = 'NOT POSSIBLE';
              
              function generate(A, B, C, D) {
              	var args = [A, B, C, D];
              	var idx = -1;
              	var out = NOT_POSSIBLE;
              	var firstN, secondN;
              
              	MAIN: {
              		args.sort(NUMERIC_ASCENDING);
              		// number has to start with 0, 1 or 2
              		if (args[0] > 2) break MAIN;
              
              		while (args[++idx] < 3) {}
              
              		// take the higest 2, 1, or 0
              		firstN = args[--idx];
              		args = pop(args, idx);
              
              		if (firstN === 2) {
              			// make sure that the first number doesn't exceed 23 and
              			// the second number 59
              			if (args[0] > 3 || args[0] > 1 && args[1] > 5)
              				break MAIN;
              			// advance to the first number < 3 or the length
              			idx = 0;
              			while (args[++idx] < 3){}
              		} else {
              			// much simpler if we have a 0 or 1, take the biggest n remaining
              			idx = args.length;
              		}
              
              		secondN = args[--idx];
              		args = pop(args, idx);
              		// if minutes number is too large, swap
              		if (args[0] > 5) {
              			out = '' + secondN + args[1] + ':' + firstN + args[0];
              		} else {
              			// if bottom number is low enough, swap for more minutes
              			out = '' + firstN + secondN + (args[1] < 6 ? ':' + args[1] + args[0] : ':' + args[0] + args[1]);
              		}
              	}
              	return out;
              }
              
              // numeric comparator for sort
              function NUMERIC_ASCENDING(x, y) {
              	return x > y ? 1 : y > x ? -1 : 0;
              }
              
              // specialized "array pop" I wrote out longhand that's very optimized; might be cheating =D
              function pop(arr, target) {
              	switch (arr.length) {
              	case 3:
              		switch (target) {
              		case 0: return [arr[1], arr[2]];
              		case 1: return [arr[0], arr[2]];
              		default: return [arr[0], arr[1]];
              		}
              	case 4:
              		switch (target) {
              		case 0: return [arr[1], arr[2], arr[3]];
              		case 1: return [arr[0], arr[2], arr[3]];
              		case 2: return [arr[0], arr[1], arr[3]];
              		default: return [arr[0], arr[1], arr[2]];
              		}
              	}
              }
              
              /* --------------- Start Speed Test --------------------- */
              let startTime = Math.floor(Date.now());
              let times = 10000;
              let timesHolder = times;
              
              while (times--) {
                let A = randNum();
                let B = randNum();
                let C = randNum();
                let D = randNum();
                generate(A, B, C, D);
                if (times == 0) {
                  let totalTime = Math.floor(Date.now()) - startTime;
                  let msg = timesHolder + ' Call Finished Within -> ' + totalTime + ' ms <-';
                  console.log(msg);
                }
              }
              function randNum() {
                return Math.floor(Math.random() * (9 - 0 + 1)) + 0;
              }
              /* --------------- END Speed Test --------------------- */

              【讨论】:

                【解决方案18】:

                我的方法是拥有一组可用数字 (stack) 和另一个具有返回值 (ret)。起初我输入了 ret 无效值“-1”。然后我对堆栈进行降序排序并循环槽以尝试分配最大可能的数字来返回堆栈。

                function swap(a, b, p1, p2) {
                  var temp = a[p1];
                  a[p1] = b[p2];
                  b[p2] = temp;
                }
                
                function t(a, b, c, d) {
                  var stack = [a, b, c, d];
                  var ret   = [-1, -1, -1, -1];
                
                  stack.sort().reverse();
                  var change = true;
                  var i = 0;
                  // this while is assigning HOURS
                  while(change === true || i < 4) {
                    change = false;
                    
                    // Assigning at first position (Hh:mm), so number must be lower or equal to 2
                    if(stack[i] <= 2 && ret[0] < stack[i]) {
                      swap(ret, stack, 0, i);
                      change = true;
                      i = 0;
                    } 
                    // Assigning at second position (hH:mm), so number must be <= 4 if number 
                    // at first position is 2, otherwise just make sure valid number 
                    // (0 to 1) is assigned at first position
                    else if(((ret[0] === 2 && stack[i] <= 4) || ret[0] < 2 && ret[0] >= 0) && ret[1] < stack[i]) {
                      swap(ret, stack, 1, i);
                      change = true;
                      i = 0;
                    }
                    else i++;
                  }
                  
                  stack.sort().reverse();
                  change = true;
                  i = 0;
                  // This while is assigning minutes
                  while(change === true || i < 4) {
                    change = false;
                    
                    if(stack[i] <= 5 && ret[2] < stack[i]) {
                      swap(ret, stack, 2, i);
                      change = true;
                      i = 0;
                    } 
                    else if(stack[i] <= 9 && ret[3] < stack[i]) {
                      swap(ret, stack, 3, i);
                      change = true;
                      i = 0;
                    }
                    else i++;
                  }
                  
                  // If return stack contains -1, invalid combination was entered
                  return Math.min.apply(Math, ret) > -1
                    ? ret[0] + "" + ret[1] + ":" + ret[2] + "" + ret[3]
                    : "NOT POSSIBLE";
                }
                
                console.log(t(6, 5, 2, 0)); // 20:56
                console.log(t(3, 9, 5, 0)); // 09:53
                console.log(t(2, 5, 6, 8)); // NOT POSSIBLE

                【讨论】:

                  【解决方案19】:

                  聚会真的迟到了,但我认为有一个非常直接的解决方案(虽然比其他解决方案更慢更丑陋)。只需遍历(无硬编码,无排列)从 2359 到 0 的所有整数值,并检查它们是否包含提供的数字:

                  Number.prototype.pad = function(size) {
                      var s = String(this);
                      while (s.length < (size || 2)) {s = "0" + s;}
                      return s;
                  }
                  
                  getHHMM = (val) => `${Math.floor(val / 100).pad(2)}:${(val % 100).pad(2)}`;
                  
                  isValidDate = value => !isNaN(new Date(`1970-01-01T${getHHMM(value)}`).getTime());
                  
                  isFit = function(a, b, c, d, value) {
                      var valStr = value.pad(4).split("").sort().join("");
                      var digStr = [a, b, c, d].sort().join("");
                      return valStr === digStr;
                  }
                  
                  generate = function(a, b, c, d) {
                      for (var i = 2359; i >= 0; i--) {
                          if (isFit(a, b, c, d, i) && isValidDate(i))
                              return getHHMM(i);
                      }
                      return "NOT POSSIBLE";
                  }
                  

                  【讨论】:

                    【解决方案20】:

                    此解决方案在 Swift 3.0 中。

                    func returnValue (_ value :inout Int, tempArray : [Int] , compareValue : Int) -> Int {
                    
                        for i in tempArray {
                    
                            if value <= i && i <= compareValue {
                                value = i
                            }
                        }
                    
                        return value
                    }
                    
                    func removeValue(_ value : Int, tempArr : inout [Int]) -> Bool {
                        let index = tempArr.index(of: value)
                        tempArr.remove(at: index ?? 0)
                        return index != nil ? true : false
                    }
                    
                    public func solution(_ A : Int, _ B : Int, _ C : Int, _ D : Int) -> String {
                    
                        var tempArray = [A, B, C, D]
                    
                        let mainArray = [A, B, C, D]
                    
                        var H1 : Int = -1, H2: Int = -1, M1 : Int = -1, M2 : Int = -1;
                    
                        H1 = returnValue(&H1, tempArray: tempArray, compareValue: 2)
                    
                        if !removeValue(H1, tempArr: &tempArray) {
                            return "NOT POSSIBLE"
                        }
                    
                        for value in tempArray {
                    
                            if H1 < 2 {
                                if H2 <= value && value <= 9 {
                                    H2 = value
                                }
                            } else {
                                if H2 <= value && value <= 3 {
                                    H2 = value
                                }
                            }
                        }
                    
                        if !removeValue(H2, tempArr: &tempArray) {
                            return "NOT POSSIBLE"
                        }
                    
                        M1 = returnValue(&M1, tempArray: tempArray, compareValue: 5)
                    
                    
                        if M1 >= 0 {
                    
                            if !removeValue(M1, tempArr: &tempArray) {
                                return "NOT POSSIBLE"
                            }
                        } else if mainArray.contains(0) || mainArray.contains(1) {
                    
                            H1 = -1
                    
                            H1 = returnValue(&H1, tempArray: mainArray, compareValue: 1)
                    
                            for value in mainArray {
                    
                                if H1 < 2 {
                                    if H2 <= value && value <= 9 {
                                        H2 = value
                                    }
                                } else {
                                    if H2 <= value && value <= 3 {
                                        H2 = value
                                    }
                                }
                            }
                    
                    
                            tempArray.removeAll()
                    
                            for value in mainArray {
                                tempArray.append(value)
                            }
                    
                    
                            var index = tempArray.index(of: H1)
                            tempArray.remove(at: index!)
                    
                            index = tempArray.index(of: H2)
                            tempArray.remove(at: index!)
                    
                            M1 = -1
                            M1 = returnValue(&M1, tempArray: tempArray, compareValue: 5)
                    
                            if !removeValue(M1, tempArr: &tempArray) {
                                return "NOT POSSIBLE"
                            }
                    
                        } else {
                            return "NOT POSSIBLE"
                        }
                    
                        // Now last we have M2 = temp.last
                    
                        if let lastValue = tempArray.last {
                            M2 = lastValue
                        }
                    
                        if M2 < 0 {
                            return "NOT POSSIBLE"
                        }
                    
                        return "\(H1)\(H2):\(M1)\(M2)"
                    }
                    
                    
                    print(solution(1,7,2,7))
                    print(solution(0,0,2,9))
                    print(solution(6,5,2,0))
                    print(solution(3,9,5,0))
                    print(solution(7,6,3,8))
                    print(solution(0,0,0,0))
                    print(solution(9,9,9,9))
                    print(solution(1,2,3,4))
                    
                     17:27
                     20:09
                     20:56
                     09:53
                     NOT POSSIBLE
                     00:00
                     NOT POSSIBLE
                     23:41
                    

                    【讨论】:

                      【解决方案21】:

                      由于输入和输出空间较小,使用查找表始终是一种选择;然而,我发现在 JavaScript 中,表格的大小对速度的影响惊人地大。

                      如果我们首先对输入进行排序以获得规范版本,以便将4,3,2,13,1,4,2 都转换为1,2,3,4,则导致有效结果的可能性不到 400 种。但是,一旦我在查找表中添加了 200 多个条目,速度就会大大下降(这可能与浏览器有关)。

                      但是,数字只有五种:

                      0,1    <- can be first digit of hours followed by any digit
                      2      <- can be first digit of hours followed by 0-3
                      3      <- can be second digit of hours after a 2 to form 23 hours
                      4,5    <- can be first digits of minutes
                      6-9    <- can only be second digit of hours or minutes
                      

                      在这些类型中,数字是可以互换的;最佳排列将是相同的:

                      2,4,0,6  ->  20:46  (ACBD)
                      2,5,1,9  ->  21:59  (ACBD)
                      

                      如果用数字类型“0”(0-1)、“2”、“3”、“4”(4-5)和“6”(6-9)来表示数字,则只有导致有效解决方案的 48 种组合,每种组合使用 16 种不同排列中的一种。事实证明,使用这些较小的查找表的代码要快得多:

                      function generate(A, B, C, D) {
                          var swap; // sorting network
                          if (A > B) { swap = A; A = B; B = swap; }
                          if (C > D) { swap = C; C = D; D = swap; }
                          if (A > C) { swap = A; A = C; C = swap; }
                          if (B > D) { swap = B; B = D; D = swap; }
                          if (B > C) { swap = B; B = C; C = swap; }
                      
                          var table = {"0000":15, "0002":15, "0003":14, "0004":14, "0006":14, "0022":15, 
                                       "0023":14, "0024":13, "0026":12, "0033":11, "0034":11, "0036":11, 
                                       "0044":11, "0046":11, "0066":10, "0222":15, "0223":14, "0224":13, 
                                       "0226":12, "0233":11, "0234": 9, "0236": 8, "0244": 7, "0246": 6, 
                                       "0266": 4, "0333": 5, "0334": 5, "0336": 5, "0344": 5, "0346": 5, 
                                       "0366": 4, "0444": 5, "0446": 5, "0466": 4, "2222":15, "2223":14, 
                                       "2224":13, "2226":12, "2233":11, "2234": 9, "2236": 8, "2244": 7, 
                                       "2246": 6, "2333": 5, "2334": 3, "2336": 2, "2344": 1, "2346": 0};
                      
                          var type = ['0','0','2','3','4','4','6','6','6','6'];
                          var key = type[A] + type[B] + type[C] + type[D];
                          var permutation = table[key];
                          if (permutation == undefined) return "NOT POSSIBLE";
                      
                          var digits = [[2,3,C,D], [2,3,D,C], [2,3,3,D], [2,3,D,3], 
                                        [A,D,B,C], [A,D,C,B], [2,A,C,D], [2,A,D,C], 
                                        [2,3,A,D], [2,3,D,A], [B,D,A,C], [B,D,C,A], 
                                        [2,B,A,D], [2,B,D,A], [C,D,B,A], [D,C,B,A]];
                      
                          var time = digits[permutation];
                          return "" + time[0] + time[1] + ':' + time[2] + time[3];
                      }
                      
                      function rndDigit() { return Math.floor(Math.random() * 10); }
                      for (var tests = 0; tests < 11; tests++) {
                          var d = [rndDigit(), rndDigit(), rndDigit(), rndDigit()];
                          document.write(d + " &rarr; " + generate(d[0],d[1],d[2],d[3]) + "<BR>");
                      }

                      【讨论】:

                      • 嗯,在我的浏览器中将其作为独立文件运行,它看起来似乎比 15ms 解决方案更快,但作为堆栈 sn-p,10,000 次调用需要 20ms。
                      【解决方案22】:

                      我最近正在解决同样的问题(虽然是 6 位数)并想出了这个非暴力解决方案:

                        #include <iostream>
                        #include <iomanip>
                      
                        int numbers[6] = { 0, 0, 0, 0, 0, 0 };
                        int input[6] = { 1, 7, 3, 3, 4, 1 };
                      
                        void buildHistogram() {
                            for (int i = 0; i < 6; ++i) {
                                numbers[input[i]]++;
                            }
                        }
                      
                        int getMaxNotExceeding(int number) {
                            for (int i = number; i >= 0; --i) {
                                if (numbers[i] > 0) {
                                    numbers[i]--;
                                    return i;
                                }
                            }
                            throw std::exception("CANNOT CREATE TIME");
                        }
                      
                        int main() {
                            try {
                                buildHistogram();
                                int hours = (getMaxNotExceeding(2) * 10);
                                if (hours < 20) {
                                  hours += getMaxNotExceeding(9);
                                } else {
                                  hours += getMaxNotExceeding(3);
                                }
                                int minutes = (getMaxNotExceeding(5) * 10) + getMaxNotExceeding(9);
                                int seconds = (getMaxNotExceeding(5) * 10) + getMaxNotExceeding(9);
                      
                                if (seconds > 59 || minutes > 59 || hours > 23) {
                                    throw std::exception("CANNOT CREATE TIME");
                                }
                                std::cout.fill('0');
                                std::cout << std::setw(2) << hours << ':' << std::setw(2) << minutes << ':' << std::setw(2) << seconds << std::endl;
                            } catch(const std::exception& ex) {
                                std::cout << ex.what() << std::endl;
                            }
                            return 0;
                        }
                      

                      【讨论】:

                        【解决方案23】:

                        function isValidNumbers(numbers){ 
                            const limitations = {gt5:0, gt4:0, gt2:0}
                            for (var key in numbers) {
                                const val = numbers[key]
                                //Only 0-9 are valid numbers
                                if (val > 9) return false 
                                //Only one number can be greater than 5
                                if (val > 5 && ++ limitations.gt5 && limitations.gt5 > 1) return false
                                //Only two numbers can be greater then 3
                                //For example 24:44 is not valid 
                                //Max possible time can be 23:59
                                if (val > 3 && ++ limitations.gt4 && limitations.gt4 > 2) return false
                                //Only 3 numbers can be greater then 2
                                if (val > 2 && ++ limitations.gt2 && limitations.gt2 > 3) return false
                            }
                            return true;
                        }
                        
                        function sortArgs(...args) {
                          return args.sort(function (a, b) { return b - a; });
                        }
                        
                        function getMaxTime(a, b, c, d){
                            if (!isValidNumbers(arguments)) return 'not possible'
                            const sortedArr = sortArgs(...arguments)
                            const has2 = sortedArr.indexOf(2);
                            let hh = []
                            let mm = []
                            sortedArr.forEach(function(val) {
                                if (val > 5) return has2 == -1 && !hh[1] ? hh[1] = val : mm[1] = val
                                if (val > 3) return has2 == -1 && !hh[1] ? hh[1] = val : !mm[0] ? mm[0] = val : mm[1] = val
                                if (val > 2) return !hh[1] ? hh[1] = val : !mm[0] ? mm[0] = val : mm[1] = val
                                return !hh[0] ? hh[0] = val : !hh[1] ? hh[1] = val : !mm[0] ? mm[0] = val : mm[1] = val
                            })  
                            //return has2
                            return `${hh[0]}${hh[1]}:${mm[0]}${mm[1]}`;
                        }
                        console.log(getMaxTime(1,2,3,4)) // "23:41"
                        console.log(getMaxTime(1,1,3,4)) // "14:31"
                        console.log(getMaxTime(6,4,2,4)) // "not possible"

                        【讨论】:

                        • 你的问题是什么?
                        【解决方案24】:
                        public static string CreateTime()
                                {
                                    int[] arr = { 5,5,6,6 };
                                    int hr_tense_max = 0;
                                    int hr_ones_max = 0;
                                    int min_tense_max = 0;
                                    int min_ones_max = 0;
                        
                                    for (int i = 0; i < arr.Length; i++)
                                    {
                                        int value = arr[i];
                                        if (value <= 2 && value > hr_tense_max)
                                        {
                                            hr_tense_max = value;
                                            continue;
                                        }
                        
                                        if (value <= 3 && value > hr_ones_max)
                                        {
                                            hr_ones_max = value;
                                            continue;
                                        }
                        
                                        if (value <= 5 && value > min_tense_max)
                                        {
                                            min_tense_max = value;
                                            continue;
                                        }
                        
                                        if (value <= 9 && value > min_ones_max)
                                        {
                                            min_ones_max = value;
                                            continue;
                                        }
                        
                        
                                    }
                                    if ((hr_tense_max * 10 + hr_ones_max) > 24 || (min_tense_max * 10 + min_ones_max) > 59) 
                                    { 
                                        return "Not Possible"; 
                                    }
                                    return $"{hr_tense_max}{hr_ones_max}:{min_tense_max}{min_ones_max}";
                                }
                        

                        【讨论】:

                          【解决方案25】:

                          Python:

                          def get_number_frequency(arr):
                              from collections import Counter
                              return dict(Counter(arr))
                          
                          def check_val(mapped_val, val):
                              if val in mapped_val:
                                  mapped_val[val] -= 1
                                  return True
                              return False
                          
                          def getMax_time(arr, n):
                              time_value = ""
                              flag = False
                              mapped_val = get_number_frequency(arr)
                              
                              for i in range(2,-1,-1):
                                  if check_val(mapped_val, i):
                                      time_value += str(i)
                                      flag = True
                                      break
                              if not flag:
                                  return ""
                              flag = False
                              
                              if time_value[0] == 2:
                                  for i in range(3,-1,-1):
                                      if check_val(mapped_val, i):
                                          flag = True
                                          time_value += str(i)
                                      break
                              else:
                                  for i in range(9, -1, -1):
                                      if check_val(mapped_val, i):
                                          flag = True
                                          time_value += str(i)
                                          break
                              time_value += ":"
                              if not flag:
                                  return ""
                              flag = False
                            
                              for i in range(5,-1,-1):
                                  if check_val(mapped_val, i):
                                      flag = True
                                      time_value += str(i)
                                      break
                             
                              if not flag:
                                  return ""
                              flag = False
                          
                              for i in range(9,-1,-1):
                                  if check_val(mapped_val, i):
                                      flag = True
                                      time_value += str(i)
                                      break
                          
                          
                              return time_value
                          
                          if __name__ == "__main__":   
                              arr = [2,2,2,2] 
                              n = len(arr)
                              print(getMax_time(arr, n)) 
                          

                          【讨论】:

                          • 您能否为您的代码 sn-p 添加更多解释?你的代码做了什么,为什么它会帮助 OP?
                          猜你喜欢
                          • 2013-01-10
                          • 1970-01-01
                          • 1970-01-01
                          • 1970-01-01
                          • 2018-11-25
                          • 1970-01-01
                          • 1970-01-01
                          • 1970-01-01
                          • 2012-11-20
                          相关资源
                          最近更新 更多