LeetCode 681 - Next Closest Time


http://bookshadow.com/weblog/2017/09/24/leetcode-next-closest-time/
Given a time represented in the format "HH:MM", form the next closest time by reusing the current digits. There is no limit on how many times a digit can be reused.
You may assume the given input string is always valid. For example, "01:34", "12:09" are all valid. "1:34", "12:9" are all invalid.
Example 1:
Input: "19:34"
Output: "19:39"
Explanation: The next closest time choosing from digits 1, 9, 3, 4, is 19:39, which occurs 5 minutes later.  It is not 19:33, because this occurs 23 hours and 59 minutes later.
Example 2:
Input: "23:59"
Output: "22:22"
Explanation: The next closest time choosing from digits 2, 3, 5, 9, is 22:22. It may be assumed that the returned time is next day's time since it is smaller than the input time numerically.

题目大意:

给定格式为HH:MM的时间time,根据其中的数字,组成距离当前时间最近的下一个时刻。

解题思路:

将time的数字取出并排序,记为stime,令X = stime[0]
从time的低位向高位枚举,将stime中恰好大于当前值的值进行替换,并将其后的所有值替换为X
若不存在这样的替换,则返回XX:XX
X.
解法2:替换数字。先把出现的数字去重排序,然后从最低位的分钟开始替换,如果低位分钟上的数字已经是最大的数字,就把低位分钟上的数字换成最小的数字,否则就将低位分钟上的数字换成下一个较大的数字。高位分钟上的数字已经是最大的数字,或则下一个数字大于5,那么直接换成最小值,否则就将高位分钟上的数字换成下一个较大的数字。小时数字也是同理,小时低位上的数字情况比较复杂,当小时高位不为2的时候,低位可以是任意数字,而当高位为2时,低位需要小于等于3。对于小时高位,其必须要小于等于2。Time: O(4*10),Space: O(10)
public String nextClosestTime(String time) {
        char[] t = time.toCharArray(), result = new char[4];
        int[] list = new int[10];
        char min = '9';
        for (char c : t) {
            if (c == ':') continue;
            list[c - '0']++;
            if (c < min) {
                min = c;
            }
        }
        for (int i = t[4] - '0' + 1; i <= 9; i++) {
            if (list[i] != 0) {
                t[4] = (char)(i + '0');
                return new String(t);
            }
        }
        t[4] = min;
        for (int i = t[3] - '0' + 1; i <= 5; i++) {
            if (list[i] != 0) {
                t[3] = (char)(i + '0');
                return new String(t);
            }
        }
        t[3] = min;
        int stop = t[0] < '2' ? 9 : 3;
        for (int i = t[1] - '0' + 1; i <= stop; i++) {
            if (list[i] != 0) {
                t[1] = (char)(i + '0');
                return new String(t);
            }
        }
        t[1] = min;
        for (int i = t[0] - '0' + 1; i <= 2; i++) {
            if (list[i] != 0) {
                t[0] = (char)(i + '0');
                return new String(t);
            }
        }
        t[0] = min;
        return new String(t);
    }  
http://hehejun.blogspot.com/2018/08/leetcodenext-closest-time.html
找字典序大于当前时间最小时间,只需要从LSB(least significant bit)开始,对处于每一位的digit d,找到大于d的最小的合法的数字,如果找不到赋予当前位4个位当中的最小数即可。因为最小的数一定可以保证小于等于2(最左边的位),所以只要输入是合法的,我们永远可以找到一个合法的解。常数时间和空间
    public String nextClosestTime(String time) {
        char[] res = time.toCharArray();
        //找到所有可用的数,排序后存起来
        char[] digits = new char[]{res[0], res[1], res[3], res[4]};
        Arrays.sort(digits);
        
        //从右到左对res进行操作,只要有当前最小单位时间的替换,返回替换后的时间
        res[4] = findNext(digits, res[4], '9');
        if (res[4] > time.charAt(4)) return String.valueOf(res);
        res[3] = findNext(digits, res[3], '5');
        if (res[3] > time.charAt(3)) return String.valueOf(res);
        res[1] = res[0] == '2' ? findNext(digits, res[1], '3') : findNext(digits, res[1], '9');
        if (res[1] > time.charAt(1)) return String.valueOf(res);
        res[0] = findNext(digits, res[0], '2');
        return String.valueOf(res);
    }
    private char findNext(char[] digits, char cur, char upper) {
        if (cur == upper) return digits[0];
        //找到cur的位置,然后加1得到下一个位置
        int pos = Arrays.binarySearch(digits, cur)+1;
        //如果下一个位置的数还是原来的数,或者超过了上限数,前进到再下一个
        while (pos < 4 && (digits[pos] == cur || digits[pos] > upper)) pos++;
        return pos == 4 ? digits[0] : digits[pos];
    }
解法一:最优解法,时间复杂度为O(4*10),空间复杂度为O(10),思路:用一个伪哈希表来存给的时间的数字,然后从第四位开始,去哈希表里找有没有比给定的第四位大而且合法的数字,如果有则返回带有这个合法数字的新的string;如果没有,就把第四位设为哈希表里的最小值。依次类推,从第四位走到第一位,如果第一位还不存在一个比它大的合法值,则四位都设为最小值,然后返回,此时对应的情况就是example2里的情况,返回的是第二天的最小时间。此解法简单易懂,而且效率很高,beats 96%的leetcoder.

  public String nextClosestTime(String time) {
    char[] t = time.toCharArray(), result = new char[4];
    int[] list = new int[10];
    char min = '9';
    for (char c : t) {
      if (c == ':')
        continue;
      list[c - '0']++;
      if (c < min) {
        min = c;
      }
    }
    for (int i = t[4] - '0' + 1; i <= 9; i++) {
      if (list[i] != 0) {
        t[4] = (char) (i + '0');
        return new String(t);
      }
    }
    t[4] = min;
    for (int i = t[3] - '0' + 1; i <= 5; i++) {
      if (list[i] != 0) {
        t[3] = (char) (i + '0');
        return new String(t);
      }
    }
    t[3] = min;
    int stop = t[0] < '2' ? 9 : 3;
    for (int i = t[1] - '0' + 1; i <= stop; i++) {
      if (list[i] != 0) {
        t[1] = (char) (i + '0');
        return new String(t);
      }
    }
    t[1] = min;
    for (int i = t[0] - '0' + 1; i <= 2; i++) {
      if (list[i] != 0) {
        t[0] = (char) (i + '0');
        return new String(t);
      }
    }
    t[0] = min;
    return new String(t);
  }


X. DFS + Brute Force

解法3:找出这四个数字的所有可能的时间组合,然后和给定时间比较,maintain一个差值最小的,返回这个string。Time: O(4^4),Space: O(4)。
int diff = Integer.MAX_VALUE;
    String result = "";

    public String nextClosestTime(String time) {
        Set<Integer> set = new HashSet<>();
        set.add(Integer.parseInt(time.substring(0, 1)));
        set.add(Integer.parseInt(time.substring(1, 2)));
        set.add(Integer.parseInt(time.substring(3, 4)));
        set.add(Integer.parseInt(time.substring(4, 5)));

        if (set.size() == 1) return time;

        List<Integer> digits = new ArrayList<>(set);
        int minute = Integer.parseInt(time.substring(0, 2)) * 60 + Integer.parseInt(time.substring(3, 5));

        dfs(digits, "", 0, minute);

        return result;
    }

    private void dfs(List<Integer> digits, String cur, int pos, int target) {
        if (pos == 4) {
            int m = Integer.parseInt(cur.substring(0, 2)) * 60 + Integer.parseInt(cur.substring(2, 4));
            if (m == target) return;
            int d = m - target > 0 ? m - target : 1440 + m - target;
            if (d < diff) {
                diff = d;
                result = cur.substring(0, 2) + ":" + cur.substring(2, 4);
            }
            return;
        }

        for (int i = 0; i < digits.size(); i++) {
            if (pos == 0 && digits.get(i) > 2) continue;
            if (pos == 1 && Integer.parseInt(cur) * 10 + digits.get(i) > 23) continue;
            if (pos == 2 && digits.get(i) > 5) continue;
            if (pos == 3 && Integer.parseInt(cur.substring(2)) * 10 + digits.get(i) > 59) continue;
            dfs(digits, cur + digits.get(i), pos + 1, target);
        }
    } 

解法二:找出这四个数字的所有可能的时间组合,然后和给定时间比较,maintain一个差值最小的,返回这个string。时间复杂度O(4^4),空间复杂度O(4)。

  int diff = Integer.MAX_VALUE;
  String result = "";

  public String nextClosestTime(String time) {
    Set<Integer> set = new HashSet<>();
    set.add(Integer.parseInt(time.substring(0, 1)));
    set.add(Integer.parseInt(time.substring(1, 2)));
    set.add(Integer.parseInt(time.substring(3, 4)));
    set.add(Integer.parseInt(time.substring(4, 5)));

    if (set.size() == 1)
      return time;

    List<Integer> digits = new ArrayList<>(set);
    int minute = Integer.parseInt(time.substring(0, 2)) * 60 + Integer.parseInt(time.substring(3, 5));

    dfs(digits, "", 0, minute);

    return result;
  }

  private void dfs(List<Integer> digits, String cur, int pos, int target) {
    if (pos == 4) {
      int m = Integer.parseInt(cur.substring(0, 2)) * 60 + Integer.parseInt(cur.substring(2, 4));
      if (m == target)
        return;
      int d = m - target > 0 ? m - target : 1440 + m - target;
      if (d < diff) {
        diff = d;
        result = cur.substring(0, 2) + ":" + cur.substring(2, 4);
      }
      return;
    }

    for (int i = 0; i < digits.size(); i++) {
      if (pos == 0 && digits.get(i) > 2)
        continue;
      if (pos == 1 && Integer.parseInt(cur) * 10 + digits.get(i) > 23)
        continue;
      if (pos == 2 && digits.get(i) > 5)
        continue;
      if (pos == 3 && Integer.parseInt(cur.substring(2)) * 10 + digits.get(i) > 59)
        continue;
      dfs(digits, cur + digits.get(i), pos + 1, target);
    }
  }
string nextClosestTime(string time) {
    vector<int> d = {
        time[0] - '0', time[1] - '0', time[3] - '0', time[4] - '0' };
    int h = d[0] * 10 + d[1];
    int m = d[2] * 10 + d[3];
    vector<int> curr(4, 0);
    int now = toTime(h, m);
    int best = now;
    dfs(0, d, curr, now, best);
    char buff[5];
    sprintf(buff, "%02d:%02d", best / 60, best % 60);
    return string(buff);
}
private:
void dfs(int dep, const vector<int>& digits, vector<int>& curr, int time, int& best) {
    if (dep == 4) {
        int curr_h = curr[0] * 10 + curr[1];
        int curr_m = curr[2] * 10 + curr[3];
        if (curr_h > 23 || curr_m > 59) return;
        int curr_time = toTime(curr_h, curr_m);
        if (timeDiff(time, curr_time) < timeDiff(time, best))
            best = curr_time;
        return;
    }            
    for (int digit : digits) {
        curr[dep] = digit;
        dfs(dep + 1, digits, curr, time, best);
    }        
}
int toTime(int h, int m) {
    return h * 60 + m;
}
int timeDiff(int t1, int t2) {
    if (t1 == t2) return INT_MAX;
    return ((t2 - t1) + 24 * 60) % (24 * 60);
}
X. Limited set - Brute Force
下面这种方法的写法比较简洁,实际上用了暴力搜索,由于按分钟算的话,一天只有1440分钟,也就是1440个时间点,我们可以从当前时间点开始,遍历一天的时间,也就是接下来的1440个时间点,得到一个新的整型时间点后,我们按位来更新结果res,对于每个更新的数字字符,看其是否在原时间点字符中存在,如果不存在,直接break,然后开始遍历下一个时间点,如果四个数字都成功存在了,那么将当前时间点中间夹上冒号返回即可
string nextClosestTime(string time) {
  string res = "0000";
  vector<int> v{600, 60, 10, 1};
  int found = time.find(":");
  int cur = stoi(time.substr(0, found)) * 60 + stoi(time.substr(found + 1));
  for (int i = 1, d = 0; i <= 1440; ++i) {
      int next = (cur + i) % 1440;
      for (d = 0; d < 4; ++d) {
          res[d] = '0' + next / v[d];
          next %= v[d];
          if (time.find(res[d]) == string::npos) break;
      }
      if (d >= 4) break;
  }
  return res.substr(0, 2) + ":" + res.substr(2);
}
http://storypku.com/2017/09/leetcode-question-681-next-closest-time/

https://www.codetd.com/article/3422355
解法1:Brute fore, 由于给的时间只到分钟,一天中有1440个分钟,也就是1440个时间点,可以从当前时间点开始,遍历一天的1440个时间点,每到一个时间点,看其所有的数字是否在原时间点字符中存在,如果不存在,直接break,然后开始遍历下一个时间点,如果四个数字都存在,说明找到了,换算成题目的时间形式返回即可。
public String nextClosestTime(String time) {
   int hour = Integer.parseInt(time.substring(0, 2));
   int min = Integer.parseInt(time.substring(3, 5));
   while (true) {            
       if (++min == 60) {
           min = 0;
           ++hour;
           hour %= 24;
       }
       String curr = String.format("%02d:%02d", hour, min);
       Boolean valid = true;
       for (int i = 0; i < curr.length(); ++i)
           if (time.indexOf(curr.charAt(i)) < 0) {
               valid = false;
               break;
           }
       if (valid) return curr;
   }
}
http://buttercola.blogspot.com/2019/03/leetcode-681-next-closest-time.html
One corner case to consider is if the time is 11:11, the next time should be 11:11 as it's for next day. But int the code since we check diff > 0, the ans will return 0. To handle this case, the initial value should be original time.
public String nextClosestTime(String time) {
   int original = getElapsedMinutes(time);
   int minDiff = Integer.MAX_VALUE;
   int ans = original;
   Set<Integer> set = new HashSet<>();
   for (int i = 0; i < time.length(); i++) {
       if (time.charAt(i) != ':') {
           set.add(Character.getNumericValue(time.charAt(i)));
       }
   }
   for (int h1 : set) {
       for (int h2 : set) {
           if (h1 * 10 + h2 < 24) {
               for (int m1 : set) {
                   for (int m2 : set) {
                       if (m1 * 10 + m2 < 60) {
                           int currTime = (h1 * 10 + h2) * 60 + (m1 * 10 + m2);
                           int diff = Math.floorMod(currTime - original, 24 * 60);
                           if (diff > 0 && diff < minDiff) {
                               ans = currTime;
                               minDiff = diff;
                           }
                       }
                   }
               }
           }
       }
   }
   return String.format("%02d:%02d", ans / 60, ans % 60);
}
private int getElapsedMinutes(String time) {
   int hour = Character.getNumericValue(time.charAt(0)) * 10 + Character.getNumericValue(time.charAt(1));
   int min = Character.getNumericValue(time.charAt(3)) * 10 + Character.getNumericValue(time.charAt(4));
   return hour * 60 + min;
}

X. Videos
Google Coding Interview (2019) - Next Closest Time (LeetCode)

花花酱 LeetCode 681. Next Closest Time - 刷题找工作 EP70

Labels

LeetCode (1432) GeeksforGeeks (1122) LeetCode - Review (1067) Review (882) Algorithm (668) to-do (609) Classic Algorithm (270) Google Interview (237) Classic Interview (222) Dynamic Programming (220) DP (186) Bit Algorithms (145) POJ (141) Math (137) Tree (132) LeetCode - Phone (129) EPI (122) Cracking Coding Interview (119) DFS (115) Difficult Algorithm (115) Lintcode (115) Different Solutions (110) Smart Algorithm (104) Binary Search (96) BFS (91) HackerRank (90) Binary Tree (86) Hard (79) Two Pointers (78) Stack (76) Company-Facebook (75) BST (72) Graph Algorithm (72) Time Complexity (69) Greedy Algorithm (68) Interval (63) Company - Google (62) Geometry Algorithm (61) Interview Corner (61) LeetCode - Extended (61) Union-Find (60) Trie (58) Advanced Data Structure (56) List (56) Priority Queue (53) Codility (52) ComProGuide (50) LeetCode Hard (50) Matrix (50) Bisection (48) Segment Tree (48) Sliding Window (48) USACO (46) Space Optimization (45) Company-Airbnb (41) Greedy (41) Mathematical Algorithm (41) Tree - Post-Order (41) ACM-ICPC (40) Algorithm Interview (40) Data Structure Design (40) Graph (40) Backtracking (39) Data Structure (39) Jobdu (39) Random (39) Codeforces (38) Knapsack (38) LeetCode - DP (38) Recursive Algorithm (38) String Algorithm (38) TopCoder (38) Sort (37) Introduction to Algorithms (36) Pre-Sort (36) Beauty of Programming (35) Must Known (34) Binary Search Tree (33) Follow Up (33) prismoskills (33) Palindrome (32) Permutation (31) Array (30) Google Code Jam (30) HDU (30) Array O(N) (29) Logic Thinking (29) Monotonic Stack (29) Puzzles (29) Code - Detail (27) Company-Zenefits (27) Microsoft 100 - July (27) Queue (27) Binary Indexed Trees (26) TreeMap (26) to-do-must (26) 1point3acres (25) GeeksQuiz (25) Merge Sort (25) Reverse Thinking (25) hihocoder (25) Company - LinkedIn (24) Hash (24) High Frequency (24) Summary (24) Divide and Conquer (23) Proof (23) Game Theory (22) Topological Sort (22) Lintcode - Review (21) Tree - Modification (21) Algorithm Game (20) CareerCup (20) Company - Twitter (20) DFS + Review (20) DP - Relation (20) Brain Teaser (19) DP - Tree (19) Left and Right Array (19) O(N) (19) Sweep Line (19) UVA (19) DP - Bit Masking (18) LeetCode - Thinking (18) KMP (17) LeetCode - TODO (17) Probabilities (17) Simulation (17) String Search (17) Codercareer (16) Company-Uber (16) Iterator (16) Number (16) O(1) Space (16) Shortest Path (16) itint5 (16) DFS+Cache (15) Dijkstra (15) Euclidean GCD (15) Heap (15) LeetCode - Hard (15) Majority (15) Number Theory (15) Rolling Hash (15) Tree Traversal (15) Brute Force (14) Bucket Sort (14) DP - Knapsack (14) DP - Probability (14) Difficult (14) Fast Power Algorithm (14) Pattern (14) Prefix Sum (14) TreeSet (14) Algorithm Videos (13) Amazon Interview (13) Basic Algorithm (13) Codechef (13) Combination (13) Computational Geometry (13) DP - Digit (13) LCA (13) LeetCode - DFS (13) Linked List (13) Long Increasing Sequence(LIS) (13) Math-Divisible (13) Reservoir Sampling (13) mitbbs (13) Algorithm - How To (12) Company - Microsoft (12) DP - Interval (12) DP - Multiple Relation (12) DP - Relation Optimization (12) LeetCode - Classic (12) Level Order Traversal (12) Prime (12) Pruning (12) Reconstruct Tree (12) Thinking (12) X Sum (12) AOJ (11) Bit Mask (11) Company-Snapchat (11) DP - Space Optimization (11) Dequeue (11) Graph DFS (11) MinMax (11) Miscs (11) Princeton (11) Quick Sort (11) Stack - Tree (11) 尺取法 (11) 挑战程序设计竞赛 (11) Coin Change (10) DFS+Backtracking (10) Facebook Hacker Cup (10) Fast Slow Pointers (10) HackerRank Easy (10) Interval Tree (10) Limited Range (10) Matrix - Traverse (10) Monotone Queue (10) SPOJ (10) Starting Point (10) States (10) Stock (10) Theory (10) Tutorialhorizon (10) Kadane - Extended (9) Mathblog (9) Max-Min Flow (9) Maze (9) Median (9) O(32N) (9) Quick Select (9) Stack Overflow (9) System Design (9) Tree - Conversion (9) Use XOR (9) Book Notes (8) Company-Amazon (8) DFS+BFS (8) DP - States (8) Expression (8) Longest Common Subsequence(LCS) (8) One Pass (8) Quadtrees (8) Traversal Once (8) Trie - Suffix (8) 穷竭搜索 (8) Algorithm Problem List (7) All Sub (7) Catalan Number (7) Cycle (7) DP - Cases (7) Facebook Interview (7) Fibonacci Numbers (7) Flood fill (7) Game Nim (7) Graph BFS (7) HackerRank Difficult (7) Hackerearth (7) Inversion (7) Kadane’s Algorithm (7) Manacher (7) Morris Traversal (7) Multiple Data Structures (7) Normalized Key (7) O(XN) (7) Radix Sort (7) Recursion (7) Sampling (7) Suffix Array (7) Tech-Queries (7) Tree - Serialization (7) Tree DP (7) Trie - Bit (7) 蓝桥杯 (7) Algorithm - Brain Teaser (6) BFS - Priority Queue (6) BFS - Unusual (6) Classic Data Structure Impl (6) DP - 2D (6) DP - Monotone Queue (6) DP - Unusual (6) DP-Space Optimization (6) Dutch Flag (6) How To (6) Interviewstreet (6) Knapsack - MultiplePack (6) Local MinMax (6) MST (6) Minimum Spanning Tree (6) Number - Reach (6) Parentheses (6) Pre-Sum (6) Probability (6) Programming Pearls (6) Rabin-Karp (6) Reverse (6) Scan from right (6) Schedule (6) Stream (6) Subset Sum (6) TSP (6) Xpost (6) n00tc0d3r (6) reddit (6) AI (5) Abbreviation (5) Anagram (5) Art Of Programming-July (5) Assumption (5) Bellman Ford (5) Big Data (5) Code - Solid (5) Code Kata (5) Codility-lessons (5) Coding (5) Company - WMware (5) Convex Hull (5) Crazyforcode (5) DFS - Multiple (5) DFS+DP (5) DP - Multi-Dimension (5) DP-Multiple Relation (5) Eulerian Cycle (5) Graph - Unusual (5) Graph Cycle (5) Hash Strategy (5) Immutability (5) Java (5) LogN (5) Manhattan Distance (5) Matrix Chain Multiplication (5) N Queens (5) Pre-Sort: Index (5) Quick Partition (5) Quora (5) Randomized Algorithms (5) Resources (5) Robot (5) SPFA(Shortest Path Faster Algorithm) (5) Shuffle (5) Sieve of Eratosthenes (5) Strongly Connected Components (5) Subarray Sum (5) Sudoku (5) Suffix Tree (5) Swap (5) Threaded (5) Tree - Creation (5) Warshall Floyd (5) Word Search (5) jiuzhang (5)

Popular Posts