Find maximum possible time HH:MM by permuting four given digits

前端 未结 23 2058
执念已碎
执念已碎 2020-11-30 02:44

I recently took a coding test for a promotion at work. This was one of the tasks I really struggled with and was wondering what is the best way to do this. I used a load of

相关标签:
23条回答
  • 2020-11-30 02:49

    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"

    0 讨论(0)
  • 2020-11-30 02:51

    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)
  • 2020-11-30 02:52

    I'd use JavaScript's Date object to determine if a particular time was valid, by parsing the string as an ISO datetime string (like 1970-01-01T62:87) and then testing !isNaN( aDateInstance.getTime() ) and comparing the Date instance with the earlier saved largest Date instance (if applicable):

    // 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';
    }
    
    0 讨论(0)
  • 2020-11-30 02:54

    Well, starting from this suggestion about permutations in JavaScript, where, given an array of values get all possible unique permutations, I got this solution:

    • Assuming you have all possible combinations with 4 digits,
    • and assuming that a right hours value is in the range 00-23
    • and assuming that a right minutes value is in the range 00-59

    You can use this simple code to perform the action:

    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));

    0 讨论(0)
  • 2020-11-30 02:55

    This solution is in 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
    
    0 讨论(0)
  • 2020-11-30 02:56

    I could do with tons of ifs and elses but i am pretty sure that's already been done. Instead i go with a different way.

    • We get all permutations of the given 4 numbers. Here i use my rotationPerm algorithm. I guess it is one of the fastest ever in JS.
    • Filter out the invalid times
    • Chose the biggest from the remaining values
    • Format as time.

    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));

    0 讨论(0)
提交回复
热议问题