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
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"
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;
}
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';
}
Well, starting from this suggestion about permutations in JavaScript, where, given an array of values get all possible unique permutations, I got this solution:
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));
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
I could do with tons of if
s and else
s but i am pretty sure that's already been done. Instead i go with a different way.
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));