5

I have numbers as x,y,z, and w. I am trying to create max possible time in 24 hours format. Example:

My approach is to sort the all numbers. Then for hours check the number less than equal 2, then for next digit in hour, check number less then equal to 4, and so on for minutes also. (0-60 minutes)

Is any other efficient approach than bruteforce solution?

ajay_t
  • 2,347
  • 7
  • 37
  • 62
  • 2
    how do you treat an input `3 3 3 3` ? If you could define that better as well please. – Naman Jan 25 '17 at 21:14
  • 3
    Please paste your code, where you try solve it – MatWdo Jan 25 '17 at 21:14
  • @nullpointer I think that qualify as an invalid input (as he already said in the question) as you can not have hour 33. – Jorge Campos Jan 25 '17 at 21:20
  • 1
    I can imagine a process where you do the following: Test to see if the order is valid, if valid add it to a list of valid times for that set of input, do this for all permutations of the numbers, using the valid list you then find the one that is the latest time. – Brendan Lesniak Jan 25 '17 at 21:23

6 Answers6

4

Simple approach would be to create all possible combinations of all the number from four digits. Then sort and pick out all the values less than 2359 (Max time allowed). After this you start with the max number and just validate if it is a correct time if not check the next biggest number.

StackFlowed
  • 6,664
  • 1
  • 29
  • 45
  • 1
    This is an improvement on the answer provided by Gassa, It eliminates a large number of invalid times with a sort + a comparison to 2359 rather than a full isValidTime() test.. You still have to validate the remaining candidates, but the first one that represents a valid time is a winner and you can skip testing the remainders. – Dale Wilson Jan 25 '17 at 22:06
3

Basically what you can do is instead of all permutations you create conditions for each value in the array. For example if we have a 2 we know the hour should be 2 for our ten spot but our ones spot for the hour can only be 3 at that point. If we have a 1 then we know our one spot for the hour can be 9. We know our minute ten spot is 5 and our max minute one spot is 9. createTime shows these conditions. The findMaxSpecific returns -1 if it isn't able to find a valid number in the given array. That way we know the time is invalid if we ever get an array returned by createTime with -1's in it. See example output.

public static int[] createTime(int[] numbers)
{
    int[] time = new int[4];
    time[0] = findMaxSpecific(numbers, 2);
    time[1] = time[0] == 2 ? findMaxSpecific(numbers, 3) : findMaxSpecific(numbers, 9);
    time[2] = findMaxSpecific(numbers, 5);
    time[3] = findMaxSpecific(numbers, 9);

    return time;
}

public static int findMaxSpecific(int[] arr, int valToFind)
{
    if(arr.length != 4)
        return -1;

    int numToFind = -1; 
    int indexToRemove = -1;


    for(int i = 0; i < arr.length; i++)
    {
        if(arr[i] <= valToFind)
        {
            if(arr[i] > numToFind)
            {
                numToFind = arr[i];
                indexToRemove = i;
            }
        }
    }

    if(indexToRemove == -1)
        return -1;

    arr[indexToRemove] = -1;

    return numToFind;
}

At the end of all this is if any value comes back as -1 we know we have an invalid time we were given

Example

        int[] time = new int[4];
        int[] numbers = {1,2,3,4};
        time = createTime(numbers);
        System.out.println(time[0] + "" + time[1] + ":" + time[2] + "" + time[3]);
        int[] numbers2 = {0,9,7,1};
        time = new int[4];
        time = createTime(numbers2);
        System.out.println(time[0] + "" + time[1] + ":" + time[2] + "" + time[3]);

        int[] numbers3 = {9,9,9,9};
        time = new int[4];
        time = createTime(numbers3);
        System.out.println(time[0] + "" + time[1] + ":" + time[2] + "" + time[3]);

Output is

23:41
19:07
-19:-19 //invalid numbers
RAZ_Muh_Taz
  • 4,059
  • 1
  • 13
  • 26
  • This example is flawed. If you have a 2 and a 1 it will try to make an hour with 2 even when it is not possible. Example 1,9,2,9 would be 19:29. You code will return it as 21:-19 – Adi Oct 09 '18 at 18:28
2

For input 1 2 9 9, the only possibility is 19:29, but what you describe picks the two first and gets 21:99, an invalid time.

Unless this is indeed a bottleneck and not a programming exercise, the most straightforward solution is to try all possible permutations of the digits, for each one, check whether it constitutes a valid time, and take the lexicographically maximal valid string.

The point is, there are fast solutions and there are correct solutions. Here, the fast solution is tricky, so if program running time is not critical, do consider the possibility to pick the slower but more obvious solution. This will perhaps give you, as a programmer, more time to tackle the other problems where running time does matter.

Sadly, Java does not seem to provide a builtin nextPermutation method, but Stackoverflow sure does.

Community
  • 1
  • 1
Gassa
  • 8,546
  • 3
  • 29
  • 49
  • Yep, unfortunately the naive way seems to be the way to go. I'd be interested in seeing if there is an algorithmic way to solve this (there probably is). – Brendan Lesniak Jan 25 '17 at 21:29
  • 1
    you don't need to do all permutations, you have certain conditions that determine if the current numbers you have can make a valid time. – RAZ_Muh_Taz Jan 25 '17 at 21:32
  • @RAZ_Muh_Taz Sure, but my point is that the time spent devising - and proving - the fast solution may be better spent elsewhere. – Gassa Jan 25 '17 at 21:37
1
input = (1,2,3,4)
ans = None
for hour in range(0, 24):
    for minute in range(0,60):
        if possible(hour, minute, input):
            ans = "%s:%s" % (hour, minute)

here your possible function should count the digits in hour, minute and input and make sure they equate.

bigballer
  • 136
  • 4
  • basically it's right, except in the function possible you need to take care of single digit hours and minutes. – Shiping Jan 26 '17 at 01:59
  • @Shiping yup. That works if you count them right. Depending on programming language, you can go ans = "%.2d:%.2d", and that adds an extra 0 in the formatting. – bigballer Jan 26 '17 at 02:42
  • actually i wrote another python script with a lookup table that's built the same way as what you showed. – Shiping Jan 26 '17 at 03:02
0

I would have a method you can give a predicate which extract the highest value which matches the predicate.

e.g.

public static int highest(List<Integer> values, Predicate<Integer> test) {
    Integer max = values.stream()
                        .filter(test)
                        .max(Comparator.natrualOrder())
                        .orElseThrow(() -> new InvalidStateException());
    values.remove(max);
    return max;
}

int digit1 = highest(list, i -> i < 3);
int digit3 = highest(list, i -> i < 6);
int digit2 = highest(list, i -> digit1 < 2 || i < 4);
int digit4 = highest(list, i -> true);
Peter Lawrey
  • 525,659
  • 79
  • 751
  • 1,130
  • 3
    Good start, but that doesn't address the issue of the hour using up a digit that you are going to need in the minute or second (i.e. 1299 -> 21: ??) – Dale Wilson Jan 25 '17 at 21:25
  • I think the first solution (before edit) would work if the list is ordered descendant, am I right? – Jorge Campos Jan 25 '17 at 21:31
  • @DaleWilson most likely you will need to try taking the values different orders until you find a valid combination. You could also try brute force and see if that is much slower. – Peter Lawrey Jan 25 '17 at 21:31
  • @JorgeCampos Not quite as 1299 requires the time be 19:29 – Peter Lawrey Jan 25 '17 at 21:32
  • How to prove that this gives the right answer for every possible input? One strategy would be to write the naive solution and compare the output on all possible inputs. The other would be to reason that considering `digit3` before `digit2` does not waste any opportunities for `digit2`. (The third one is to let the tester check it for you if it is an exercise from an online judge.) However, the answer looks incomplete without any proof at all. – Gassa Jan 25 '17 at 21:47
  • @Gassa its meant to be incomplete to give the OP a chance to work it out rather than do the exercise for him/her. – Peter Lawrey Jan 25 '17 at 21:54
0

Interesting problem. Seems a little bit more complex than it appears. Here is a python script for the problem.

def getmin(num):   # check if two digits are valid for minutes
    min = -1
    sum = num[0] * 10 + num[1]
    if sum < 60:
        min = sum
    sum = num[1] * 10 + num[0]
    if sum < 60 and min < sum:
        min = sum
    return min

def maxtime(num):
    hour = -1
    min = -1
    h1 = 0
    h2 = 0
    for i in range(4):
        for j in range(4):  # these two loops are to get maxi hour, if possible
             if i != j:
                 sum = num[i] * 10 + num[j]
                 if hour < sum and sum < 24:
                     c = num[:]     # get a copy of input digits
                     if i > j:      # delete numbers used in hour
                         del c[i]
                         del c[j]
                     else:
                         del c[j]
                         del c[i]
                     if getmin(c) > -1: 
                         h1 = i
                         h2 = j
                         hour = sum
    if hour > -1:
        if h2 > h1:      # delete numbers used in hour
            del num[h2]
            del num[h1]
        else:
            del num[h1]
            del num[h2]

        min = getmin(num)

        if min > -1:
            print(str(hour) + ':' + str(min))

    if hour < 0 or min < 0:
        print("no solution")

maxtime([4, 8, 1, 9])
maxtime([7, 3, 4, 2])
maxtime([9, 2, 2, 5])
maxtime([9, 2, 7, 3])

#19:48
#23:47
#22:59
#no solution
Shiping
  • 1,203
  • 2
  • 11
  • 21