9
\$\begingroup\$

Yesterday, as part of a IQ-style test, I got this interesting question:

The time on a 24-hour clock is 11:43. What is the least number of minutes I should wait before the same digits are on the screen again (in any valid 24-hour time order)?

The answer's 91 minutes, if you were wondering!

This stuck in my mind, and it finds its way... here. In an adapted form, however... Your task is, given a 24-hour time string in the format HH:MM (or in any other way as long as it provides HH and MM), shift the digits around until you find 24-hour time strings that would be in the same day counting forwards, and pick the one whose distance to the input is the shortest. Then return the number of minutes to the picked time string as an integer, using default output rules.

Method:

See above.

Input:

Allow facilities for input such that 2 digits of hours and 2 digits of minutes are provided. Do not worry about invalid input (example: 25:12, 1:34 [01:34 will be correct, however], and 05:89).

You cannot use 12-hour system.

Output:

An integer. Note that it should be in minutes, not seconds or any other unit (this is fixed)

Return a distinct value (like 1440, an error, etc. I'm using "Nil" in the test-cases) when no valid shifted 24-hour time string can be created until 23:59.

Test cases:

Input (HH:MM) -> Output (Int or "Nil")

11:43 -> 91
01:01 -> 9
17:38 -> 59
14:21 -> 413
13:20 -> 413
23:41 -> Nil
00:00 -> Nil

Scoring:

This is , so shortest answer wins!

\$\endgroup\$
13
  • 8
    \$\begingroup\$ You still didn't explain why 21:14 can't come from 14:21 \$\endgroup\$
    – l4m2
    Feb 10, 2023 at 9:08
  • 1
    \$\begingroup\$ Can I pass time to my function as two numbers i.e. f(hours,minutes) or it must be a string f('hh:mm')? \$\endgroup\$
    – EzioMercer
    Feb 10, 2023 at 10:04
  • 1
    \$\begingroup\$ You can, as long as 03 does not get parsed as 3. \$\endgroup\$ Feb 10, 2023 at 10:07
  • 2
    \$\begingroup\$ But there is no number 03. You can write f(03,08) but it will be the same as f(3,8) but it doesn't affect to the algorithm or result. Passing numbers instead of string(s) just allow me to not use split method and/or not convert strings to numbers so it saves me some bytes \$\endgroup\$
    – EzioMercer
    Feb 10, 2023 at 10:14
  • 6
    \$\begingroup\$ Suggested edge case: 00:00 -> Nil \$\endgroup\$
    – Arnauld
    Feb 10, 2023 at 11:59

14 Answers 14

6
\$\begingroup\$

Wolfram Language (Mathematica), 135 bytes

Min@(s=Select)[(x@#~f~60-a~f~60)&/@s[Permutations[p=#],(w=x@#;24>w[[1]]>=#&@@(a=x@p)&&w[[2]]<60)&],#>0&]&
x=BlockMap[f=FromDigits,#,2]&

Try it online!

-6 bytes from @att

\$\endgroup\$
2
  • \$\begingroup\$ Finally a non builtin answer :P \$\endgroup\$
    – Seggan
    Feb 10, 2023 at 16:12
  • \$\begingroup\$ x=BlockMap[f=FromDigits,#,2]& \$\endgroup\$
    – att
    Feb 11, 2023 at 1:02
4
\$\begingroup\$

05AB1E, 24 bytes

œ2δôʒŽ9¦2ô‹P}60δβć-ʒ0›}ß

Input as a single 4-digit string in the format HHmm. Outputs an empty string if there is no result available.

Try it online or verify all test cases.

Explanation:

œ            # Get all permutations of the (implicit) input-string
  δ          # Map over each permutation:
 2 ô         #  Split it into parts of size 2 (to split HH and mm)
    ʒ        # Filter this list of [HH,mm] by:
     Ž9¦     #  Push compressed integer 2460
        2ô   #  Split it into parts of size 2 as well: [24,60]
          ‹  #  Check [HH<24,mm<60]
           P #  And check if both are truthy by taking the product
    }  δ     # After the filter: map over the remaining [HH,mm]:
     60 β    #  Convert it from a base-60 list to a base-10 integer
ć            # Extract head; pop and push remainder-list and first item separately
 -           # Subtract this head (the input) from all other valid permutations
  ʒ0›}       # Only keep all positive integers from the list with a filter on 0>
             # (a.k.a. keep all integers for times later than the input-time)
      ß      # After the filter: pop and leave the minimum
             # (which is output implicitly as result)

See this 05AB1E tip of mine (section How to compress large integers?) to understand why Ž9¦ is 2460.

\$\endgroup\$
4
\$\begingroup\$

JavaScript (Node.js), 84 bytes

x=>(g=y=>++y>2399?+g:y%100<60?(e=t=>[...1e4+t+g].sort()+0)(x)==e(y)||g(y)+1:g(y))(x)

Try it online!

\$\endgroup\$
4
  • 1
    \$\begingroup\$ Input must be 2 digits for each part. \$\endgroup\$
    – Shaggy
    Feb 10, 2023 at 18:48
  • \$\begingroup\$ @Shaggy The challenge doesn't say that? \$\endgroup\$
    – Etheryte
    Feb 11, 2023 at 13:57
  • \$\begingroup\$ @Etheryte, see the "input" section of the spec which specifies that they must be 2 digits each and provides the example that 1:34 is invalid while 01:34 is valid. \$\endgroup\$
    – Shaggy
    Feb 11, 2023 at 16:51
  • \$\begingroup\$ @Shaggy I feel like you might be misreading the sentence, it explicitly says that you don't have to worry about invalid input. \$\endgroup\$
    – Etheryte
    Feb 11, 2023 at 19:01
4
\$\begingroup\$

JavaScript (ES6), 96 bytes

Expects ("HH")("MM"). Returns NaN for Nil.

h=>F=(m,s=h+m)=>(m=-~m%60)||++h<24?(g=s=>[...s].sort().slice(-4)+0)(s)==g("00"+h+m)||1+F(m,s):+F

Try it online!

Commented

h =>           // outer function taking h = hours
F = (          // inner recursive function taking
  m,           //   m = minutes
  s = h + m    //   s = concatenation of the original hours and minutes
) =>           //
(m = -~m % 60) // increment the minutes modulo 60
||             // ignore the next statement if the result is not 0
++h < 24       // otherwise, increment the hours and make sure they are
?              // less than 24; if successful:
  ( g = s =>   //   g is a helper function taking a string s
    [...s]     //   split s into a list of characters
    .sort()    //   sort them lexicographically
    .slice(-4) //   take the last 4 characters
    + 0        //   coerce back to a string with a trailing '0'
  )(s) ==      //   invoke g with s and compare the result with
  g(           //   the same operation applied to ...
    "00" +     //     two leading zeros
    h + m      //     followed by h, followed by m
  )            //
  ||           //   stop if it matches; otherwise,
    1 +        //     increment the final result
    F(m, s)    //     and do a recursive call
:              // else:
  +F           //   force the result to NaN and stop
\$\endgroup\$
1
  • 1
    \$\begingroup\$ 89 \$\endgroup\$
    – l4m2
    Feb 10, 2023 at 12:29
3
\$\begingroup\$

Vyxal g, 24 23 22 bytes

Ṗ½'‛0xC½<Π;ƛE60β;ḣ$-'Ṡ

Try it Online!

Port of Kevin Cruijssen's 05AB1E answer. Input as a string, "HHmm".

-1 thanks to AndrovT in chat
-1 thanks to lyxal

Explanation

Ṗ½'‛0xC½<Π;ƛE60β;ḣ$-'Ṡ  # Implicit input
Ṗ                       # Permutations
 ½                      # Split each in half
  '       ;             # Filter:
   ‛0xC½                #  Push [24, 60]
        <               #  Less than [24, 60]?
         Π              #  Both are true?
           ƛ    ;       # Map:
            E           #  Convert to integer
             60β        #  Convert from base-60
                 ḣ$     # Extract head and swap
                   -    # Subtract head from rest
                    '   # Filter:
                     Ṡ  #  Positive integers only
                        # g flag gets minimum
                        # Implicit output
\$\endgroup\$
2
3
\$\begingroup\$

Python, 132 bytes

lambda x:(a:=x.split(':'),b:=int(a[0])*60+int(a[1]),*[i for i in range(b+1,1440)if sorted(f"{i%60:02}:{i//60:02}")==sorted(x)])[2]-b

Attempt This Online!

Throws a error if there is no valid output.

Python, 113 bytes

lambda x,y:(b:=x*60+y,*[i for i in range(b+1,1440)if sorted((e:="%02d%02d")%divmod(i,60))==sorted(e%(x,y))])[1]-b

Attempt This Online!

Takes input as 2 numbers

\$\endgroup\$
2
  • \$\begingroup\$ My rules allow you to take 2 digits of hour and minute without having to provide it as HH:MM; I suppose you could shave off a few bytes with that (by taking input as a list or something) \$\endgroup\$ Feb 10, 2023 at 9:53
  • 3
    \$\begingroup\$ Why not use "%02d"*2 for the string in the second solution? Edit: can also set the signature to lambda x,y,z=sorted: and replace two sorted() calls with z() \$\endgroup\$ Feb 12, 2023 at 8:49
3
\$\begingroup\$

Charcoal, 42 bytes

≔↨I⪪θ:⁶⁰ηI⌊Φ…¹⁻¹⁴⁴⁰η⬤I…¹χ⁼№θλ№I↨¹⁰⁰↨⁺ηι⁶⁰λ

Try it online! Link is to verbose version of code. Outputs None if there is no solution. Explanation:

≔↨I⪪θ:⁶⁰η

Calculate the number of minutes since midnight.

I⌊Φ…¹⁻¹⁴⁴⁰η⬤I…¹χ⁼№θλ№I↨¹⁰⁰↨⁺ηι⁶⁰λ

Create a range from 1 until the number of minutes until the next midnight, filter on those that, when formatted as a time, contain identical counts of digits, and output the minimum. Note that I don't count 0 digits as all times have four digits so if the counts of the other digits are correct then so will the counts of the zero digits be; this avoids having to actually format the time.

\$\endgroup\$
3
\$\begingroup\$

JavaScript, 109 bytes

Without recursion:

(h,m)=>{for(k=1,t=h*60+m;t++<1440;++k)if((a=(h,m)=>+[...''+h+m].sort().join``)(h,m)==a(t/60|0,t%60))return k}

Try it

f=(h,m)=>{for(k=1,t=h*60+m;t++<1440;++k)if((a=(h,m)=>+[...''+h+m].sort().join``)(h,m)==a(t/60|0,t%60))return k}

[
  '11:43', // -> 91
  '01:01', // -> 9
  '17:38', // -> 59
  '14:21', // -> 413
  '13:20', // -> 413
  '23:41', // -> undefined
].forEach(t => {
  const [hours, minutes] = t.split`:`.map(x=>+x);

  const additional = f(hours, minutes);

  if (additional === undefined) {
    console.log(undefined);
    return;
  }

  const getTime = (h,m) => {
    const now = new Date();
    now.setHours(h+1);
    now.setMinutes(m);
    
   const timeParts = now.toJSON().split`T`.flatMap(x=>x.split`:`);

    return [timeParts[1], timeParts[2]].join`:`
  }

  const oldTime = getTime(hours, minutes);
  const newTime = getTime(hours, minutes + additional);

  console.log(`${oldTime} + ${additional} minutes = ${newTime}`);
})

\$\endgroup\$
3
  • \$\begingroup\$ h & m must be taken as 2 digit strings so, unfortunately, this is invalid. \$\endgroup\$
    – Shaggy
    Feb 10, 2023 at 18:16
  • 1
    \$\begingroup\$ @Shaggy "or in any other way as long as it provides HH and MM" - you can pass 05 as h and 09 as m it just automatically be converted to 5 and 9 \$\endgroup\$
    – EzioMercer
    Feb 10, 2023 at 18:36
  • \$\begingroup\$ @Shaggy The challenge doesn't say that the inputs need to be strings. \$\endgroup\$
    – Etheryte
    Feb 11, 2023 at 13:55
3
\$\begingroup\$

Perl 5, 99 bytes

sub{"@{[grep{s|1(..)([0-5].)|$1:$2@{[sort/./g]},|}1e4..12359]}"=~/$_[0]((.+),.*?)\2/&&$1=~y///c/16}

Try it online!

Creates a long string of all HH:MM in a day (all 24*60 of them) and adds the four digits sorted after each of those timestamps in the same long string. Searches the long string for the five char input HH:MM and collects the sorted digits behind it with (.+), and searches for those same sorted digits further down the long string with \2. The number of chars jumped ahead to find them divided by 16 is the number of minutes.

\$\endgroup\$
0
2
\$\begingroup\$

Excel, 175 171 bytes

=LET(
    a,A1,
    b,1440,
    c,{1;2;4;5},
    d,TEXT(SEQUENCE(,b)/b,"hh:mm"),
    e,BYCOL(MID(d,c,1),LAMBDA(x,CONCAT(SORT(x)))),
    f,0+IF(e=CONCAT(SORT(MID(a,c,1))),d),
    b*(XLOOKUP(a+1/b,f,f,,1)-a)
)

Input as string in format "hh:mm" in cell A1. Error returned if no valid output.

\$\endgroup\$
1
\$\begingroup\$

Thunno, \$ 42 \log_{256}(96) \approx \$ 34.57 bytes

DLzP.Je2APiEgAu60<s24<&ke60AdEDAJsZT_g0>km

Attempt This Online!

Port of Kevin Cruijssen's 05AB1E answer. Input as a string, "HHmm".

Explanation

DLzP                   # Get the permutations of the input string
    .J                 # Join each inner list into a single string
      e                # Map over this list:
       2APi            #  Split into two pieces and convert to an integer
           E           # (End map)
            g          # Filter this list:
             Au        #  Dump onto the stack (last item of list on top of stack)
               60<     #  Is the last item less than 60?
                  s24< #  Is the first item less than 24?
&                      #  Are both of the above true?
 k                     # (End filter)
  e                    # Map over this list:
   60Ad                #  Convert from base-60
       E               # (End map)
        DAJ            # Duplicate and get the first item
           sZT         # Swap and remove the first item
              _        # Subtract the first item from the rest
               g       # Filter this list:
                0>     #  Is the number greater than 0?
                  k    # (End filter)
                   m   # Push the minimum value of this list
                       # Implicit output
\$\endgroup\$
1
\$\begingroup\$

Julia 1.0, 107 102 bytes

using Dates
!x=(f=Minute;~q=sort(["$q"...]);t=Time(x);max(f(tonext(i->~i==~t,t,step=f(1))-t).value,0))

Try it online!

In Julia 1.8, the function will return 0 for inputs with no solution (example: !"23:41"). The TIO link only supports Julia 1.0, which fails for these inputs, since Dates.tonext doesn't stop at "23:59".

  • Renaming Dates.Minute a f saves a byte.
  • The subfunction ~ returns a sorted list of digits for comparison.
  • This solution relies on Dates.tonext, which I've used in another challenge. In Julia 1.8, it returns a negative value for inputs with no solution, so max is used to filter these out. A limit parameter also exists, but this would return an error instead of a NULL value.
  • -5 bytes thanks to MarcMush: replace string(q) with "$q"
\$\endgroup\$
1
  • 1
    \$\begingroup\$ -5 bytes: string(q) => "$q" \$\endgroup\$
    – MarcMush
    Feb 13, 2023 at 22:54
1
\$\begingroup\$

Nekomata, 24 bytes

↕ᵃ{¢b100B"<∩"e<60d}-_Paṁ

Attempt This Online!

Another port of Kevin Cruijssen's 05AB1E answer.

Take input as a list of four digits.

↕               Get a permutation of the input
 ᵃ              Apply the following block to both the input and the permutation
  {             Start the block
   ¢b               Get a number from base 10 digits
     100B           Convert the number to a list of digits in base 100
"<∩"e<              Check that the two numbers are smaller than [24,60] respectively
     60d            Get a number from base 60 digits
        }       End the block
         -_     Subtract and negate
           P    Check if the result is positive
            a   Get a list of all possible results
             ṁ  Get the minimum
\$\endgroup\$
0
\$\begingroup\$

J, 59 58 bytes

(e.*1+i.~)&([:/:~@,"%.10 10&#:)(+1+[:i.1440-])&.(24 60&#.)

Try it online!

  • (+1+[:i.1440-])&.(24 60&#.) Calculates every absolute minute of the day (0 to 1439 scale), starting at the current hour and up, and then converts back to hh:mm form.
  • ...&([:/:~@,"%.10 10&#:) Converting both the input and the candidate list from the previous step into sorted lists of digits...
  • (e.*1+i.~) Is the input an element of the candidate list (returns 0 or 1) times one plus its index within the candidate list. This returns 0 for no match, and the number of minutes we have to wait otherwise.
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.