夯实算法-给定数字能组成的最大时间

127 阅读2分钟

题目:LeetCode

给定一个由 4 位数字组成的数组,返回可以设置的符合 24 小时制的最大时间。

24 小时格式为 "HH:MM" ,其中 HH 在 00 到 23 之间,MM 在 00 到 59 之间。最小的 24 小时制时间是 00:00 ,而最大的是 23:59 。从 00:00 (午夜)开始算起,过得越久,时间越大。

以长度为 5 的字符串,按 "HH:MM" 格式返回答案。如果不能确定有效时间,则返回空字符串。

示例 1:

输入: arr = [1,2,3,4]
输出: "23:41"
解释: 有效的 24 小时制时间是 "12:34""12:43""13:24""13:42""14:23""14:32""21:34""21:43""23:14""23:41" 。这些时间中,"23:41" 是最大时间。

示例 2:

输入: arr = [5,5,5,5]
输出: ""
解释: 不存在有效的 24 小时制时间,因为 "55:55" 无效。

示例 3:

输入: arr = [0,0,0,0]
输出: "00:00"

示例 4:

输入: arr = [0,0,1,0]
输出: "10:00"

提示:

  • arr.length == 4
  • 0 <= arr[i] <= 9

解题思路

对于一个24小时格式的时间 HH:MM, 这里要明确两点:

  • HH值的范围为[0,23], 即0<=HH<=23;
  • MM值的范围为[0,59], 即0<=MM<=59; 所以, 明确了HH和MM的范围, 这里就用不着全排列了找所有的可能组合了, 只需要在范围内找HH和MM的值即可。 步骤如下:
  • 对arr数组进行排序;
  • 用left和right双指针从左往右遍历数组arr: --(1) 以左指针left指向的值arr[left]为十位数, 右指针right指向的值arr[right]为个位数进行组合, 寻找小于等于23, 并使HH可能最大的值;
  • 遍历一遍数组arr, 统计大于等于6的数字的个数记为maxThanSix;
  • 若maxThanSix小于2, 则: --(1) 以右指针right指向的值arr[right]为十位数, 左指针left指向的值arr[left]为个位数进行组合, 寻找小于等于23, 并使HH可能最大的值;
  • 若没有找到一个组合使0<=HH<=23, 则直接返回空字符串;
  • 将剩下两个没有使用的数字进行组合, 寻找小于等于59, 并使MM可能最大的组合;
  • 若没有找到一个组合使0<=MM<=59, 则直接返回空字符串;
  • 将HH和MM拼接成字符串, 这里需要注意, 当HH和MM不足两位数时, 前面用0补足.

由题意分析知:根据数组中 >=6 的数字个数来,选择策略交换数组元素的顺序;

  • 当有3位 >=6 的数时,直接返回"",因为没有一个时间能有超过3位 >=6 的数;
  • 当有2位 >=6 的数时,这时候的第一位只能取0/1,因为第三位不能取 >=6 的数,而仅当第一位位0/1时,第二位可以取09也就是 >=6的数;
  • 当有1/0位 >=6的 数时,就可以按照第一位 02,第二位根据第一位的大小取 04 或者 09,第三位取 0~5,第四位自动确认;

代码实现

public String largestTimeFromDigits(int[] arr) {
    StringBuilder sb = new StringBuilder();
    int count = 0;
    for (int i = 0; i < 4; i++) {
        if (arr[i] > 5) {
            count++;
        }
    }
    //当有三位6或以上的数时,直接返回""
    if (count > 2) {
        return "";
    }
    //当有两位6或以上的数时,第一位只能取0/1
    if (count == 2) {
        if (find(arr, 0, 1) == -1) {
            return "";
        }
        if (find(arr, 1, 9) == -1) {
            return "";
        }
        if (find(arr, 2, 5) == -1) {
            return "";
        }
        //当有0/1位6或以上的数时
    } else {
        //第一位,从0-2的最大值
        if (find(arr, 0, 2) == -1) {
            return "";
        }
        //若第一位是2,则为剩下两位从0-3的最大值
        if (arr[0] == 2) {
            if (find(arr, 1, 3) == -1) {
                return "";
            }
            //第二位,若第一位是1/0,则为剩下两位从0-9的最大值
        } else {
            if (find(arr, 1, 9) == -1) {
                return "";
            }
        }
        //第三位,剩下两位0-5的最大值
        if (find(arr, 2, 5) == -1) {
            return "";
        }
    }
    sb.append(arr[0]);
    sb.append(arr[1]);
    sb.append(":");
    sb.append(arr[2]);
    sb.append(arr[3]);
    return sb.toString();

}
public int find(int[] arr, int index, int target) {
    int length = arr.length;
    int findNum = -1;
    int sign = -1;
    int temp;
    for (int i = index; i < length; i++) {
        if (arr[i] <= target) {
            if (arr[i] > findNum) {
                findNum = arr[i];
                sign = i;
            }
        }
    }
    if (findNum != -1) {
        temp = arr[index];
        arr[index] = findNum;
        arr[sign] = temp;
    }

    return findNum;
}

运行结果

Snipaste_2023-03-02_22-20-35.png

复杂度分析

  • 空间复杂度:O(n)O(n)
  • 时间复杂度:O(nlogn)O(nlogn)

掘金(JUEJIN)  一起分享知识, Keep Learning!