【问题标题】:Generating time from numbers从数字生成时间
【发布时间】:2017-06-11 05:36:03
【问题描述】:

我有 x、y、z 和 w 等数字。 我正在尝试以 24 小时格式创建最大可能时间。 示例:

我的方法是对所有数字进行排序。然后对于小时检查小于等于 2 的数字,然后对于小时中的下一个数字,检查小于等于 4 的数字, 等几分钟也。 (0-60 分钟)

除了蛮力解决方案还有其他有效的方法吗?

【问题讨论】:

  • 你如何处理输入 3 3 3 3 ?如果您也可以更好地定义,请。
  • 请将您的代码粘贴到您尝试解决的地方
  • @nullpointer 我认为这有资格作为无效输入(正如他在问题中已经说过的那样),因为你不能有 33 小时。
  • 我可以想象一个您执行以下操作的过程:测试以查看订单是否有效,如果有效将其添加到该组输入的有效时间列表中,对所有排列执行此操作这些数字,使用有效的列表,然后您会找到最新时间的数字。

标签: java algorithm


【解决方案1】:

简单的方法是从四位数字中创建所有数字的所有可能组合。然后排序并挑选出所有小于 2359(允许的最大时间)的值。在此之后,您从最大数字开始,如果不检查下一个最大数字,则只需验证它是否是正确的时间。

【讨论】:

  • 这是对 Gassa 提供的答案的改进,它通过排序 + 与 2359 的比较而不是完整的 isValidTime() 测试来消除大量无效时间。你仍然需要验证剩下的候选者,但代表有效时间的第一个是获胜者,您可以跳过对剩余部分的测试。
【解决方案2】:

基本上,您可以做的不是所有排列,而是为数组中的每个值创建条件。例如,如果我们有一个 2,我们知道十个位置的小时应该是 2,但那时我们一个小时的位置只能是 3。如果我们有一个 1,那么我们知道我们一小时的一个点可以是 9。我们知道我们的十分钟点是 5,我们的最大分钟点是 9。createTime 显示了这些条件。如果 findMaxSpecific 在给定数组中找不到有效数字,则返回 -1。这样,如果我们得到一个由 createTime 返回的带有 -1 的数组,我们就知道时间是无效的。查看示例输出。

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

最后,如果任何值返回为 -1,我们就知道我们得到的时间无效

例子

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

输出是

23:41
19:07
-19:-19 //invalid numbers

【讨论】:

  • 这个例子有缺陷。如果你有一个 2 和一个 1,即使不可能,它也会尝试用 2 创造一个小时。示例 1,9,2,9 将是 19:29。您的代码会将其返回为 21:-19
【解决方案3】:

对于输入1 2 9 9,唯一的可能是19:29,但是你描述的先选择两个,然后得到21:99,一个无效的时间。

除非这确实是一个瓶颈而不是编程练习,否则最直接的解决方案是尝试所有可能的数字排列,对于每一个,检查它是否构成有效时间,并取字典序上最大的有效字符串。

关键是,有快速的解决方案,也有正确的解决方案。 在这里,快速解决方案很棘手,因此如果程序运行时间不重要,请考虑选择较慢但更明显的解决方案的可能性。 作为一名程序员,这也许会给你更多时间来解决运行时间很重要的其他问题。

遗憾的是,Java 似乎没有提供内置的 nextPermutation 方法,而是 Stackoverflow sure does

【讨论】:

  • 是的,不幸的是,天真的方式似乎是要走的路。我很想看看是否有解决这个问题的算法方法(可能有)。
  • 你不需要做所有的排列,你有一定的条件来确定你当前拥有的数字是否可以成为一个有效的时间。
  • @RAZ_Muh_Taz 当然,但我的意思是,花时间设计和证明快速解决方案可能会更好地花在其他地方。
【解决方案4】:
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)

您的possible 函数应计算小时、分钟和输入中的数字,并确保它们相等。

【讨论】:

  • 基本上是对的,除了在函数中你可能需要处理个位数的小时和分钟。
  • @Shiping 是的。如果你数对了,那就行得通。根据编程语言,您可以使用 ans = "%.2d:%.2d",这会在格式中添加一个额外的 0。
  • 实际上我编写了另一个带有查找表的 python 脚本,其构建方式与您展示的相同。
【解决方案5】:

我会有一种方法,您可以给出一个谓词,该谓词提取与谓词匹配的最高值。

例如

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

【讨论】:

  • 好的开始,但这并不能解决小时用完您在分钟或秒内需要的数字的问题(即 1299 -> 21: ??)
  • 我认为如果列表是按后代排序的,第一个解决方案(编辑前)会起作用,对吗?
  • @DaleWilson 很可能您需要尝试采用不同的顺序,直到找到有效的组合。您也可以尝试蛮力,看看是否会慢得多。
  • @JorgeCampos 不像 1299 要求的时间是 19:29
  • 如何证明这对每个可能的输入都给出了正确的答案?一种策略是编写简单的解决方案并比较所有可能输入的输出。另一个原因是在digit2 之前考虑digit3 不会浪费digit2 的任何机会。 (第三个是如果是在线评委的练习,让测试员帮你检查。)但是,没有任何证据,答案看起来不完整。
【解决方案6】:

有趣的问题。似乎比看起来要复杂一些。这是一个解决问题的python脚本。

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2016-11-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多