• [LintCode] Find the Missing Number II


    Giving a string with number from 1 to n in random order, but miss 1 number.Find that number.

    You can assume n <= 30

    Example

    Given n = 20, str = 19201234567891011121314151618

    return 17

    Solution 1. DFS 

    Algorithm.

    1. set a 1D boolean array: exist[0........n] to track a number from 1 to n is found or not.

    2. starting from index i, get 2 digits d1 and d2 and do the following in order.

      a. d1 == 0:  return false for invalid split;

      b. d1 != 0 && exist[d1] == false:   get a valid unchecked 1 digit number, set exist[d1] to true and keep searching from index i + 1;

        if the searching from i + 1 returns true, then the current search from i also returns true;

        if it returns false, backtrack exist[d1] to false and proceed to case c.

      c. d <= n && exist[d] == false:  get a valid unchecked 2 digits numbers, set exist[d] to true and keep searching from index i + 2;

          if the searching from i + 2 returns true, then the current search from i also returns true;

       if it returns false, backtrack exist[d] to false and the current search from i returns false as we've already exhausted all possible

          splits without finding a valid split.

    3. After the search from index 0 finishes, the boolean array exist is correctly updated. Scan from index 1 to n and find the index k where exist[k] = false.

    Return k as the missing number. 

     1 public class Solution {
     2     /**
     3      * @param n an integer
     4      * @param str a string with number from 1-n
     5      *            in random order and miss one number
     6      * @return the missing integer
     7      */
     8     public int findMissing2(int n, String str) {
     9         if(n < 1 || str == null){
    10             return 0;
    11         }
    12         boolean[] exist = new boolean[n + 1];
    13         for(int i = 0; i <= n; i++){
    14             exist[i] = false;
    15         }
    16         dfs(str, 0, exist, n);
    17         int val = 1;
    18         for(; val <= n; val++){
    19             if(!exist[val]){
    20                 break;    
    21             }
    22         }
    23         return val;
    24     }
    25     private boolean dfs(String str, int startIdx, boolean[] exist, int maxNum){
    26         if(startIdx >= str.length()){
    27             return true;
    28         }
    29         if(startIdx == str.length() - 1){
    30             int d = str.charAt(startIdx) - '0';
    31             if(d == 0 || exist[d]){
    32                 return false;
    33             }
    34             else{
    35                 exist[d] = true;
    36                 return true;
    37             }
    38         }
    39         int d1 = str.charAt(startIdx) - '0';
    40         int d2 = str.charAt(startIdx + 1) - '0';
    41         int d = d1 * 10 + d2;
    42         //first digit is 0, no valid way to keep searching
    43         if(d1 == 0){
    44             return false;
    45         }
    46         //can get a valid unchecked 1 digit number
    47         if(!exist[d1]){
    48             exist[d1] = true;
    49             if(dfs(str, startIdx + 1, exist, maxNum)){
    50                 return true;
    51             }
    52             exist[d1] = false;
    53         }
    54         //can get a valid unchecked 2 digits number
    55         if(d <= maxNum && !exist[d]){
    56             exist[d] = true;
    57             if(dfs(str, startIdx + 2, exist, maxNum)){
    58                 return true;
    59             }
    60             exist[d] = false;
    61         }            
    62         //can't get either a 1 or 2 digits unchecked number
    63         return false;
    64     }
    65 }

    To correctly get the missing number,  we should check the possiblity of splitting 1 digit before checking splitting 2 digits. Swaping the order of these

    two steps yields incorrect answer. The reason for this is discussed in solution 2.

     Solution 2. DFS

    Solution 1 uses the condition n <= 30, so when deciding whether keep searching, it only checks the next 2 digits.  The disadvantage of this solution 

    is that it does not extend well if n is changed to more than 2 digits. 

    Solution 2 does not use the condition that n can have at most 2 digits, so it is a better in this matter. 

    The algorithm of this solution is as follows.

    1. starting from the current digit, check if it is 0; if it is 0, return as we hit an invalid splitting.

    2. if it is not 0 and <= n, set its checked flag to true and keep searching starting from the next digit.

    3. after done searching, backtrack the current number's checked flag to false. 

    4. include the next digit to the current number; repeat steps 2 and 3 until the current number is > n.

    Important note: 

    To get the correct result, a found boolean flag must be used to make sure a correct answer does not 

    get overwritten by an incorrect answer.

    For example, str = "1234567891011" and n = 12.

    The only right split is {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11} and the missing integer is 12;

    Another split of {12, 3, 4, 5, 6, 7, 8, 9, 10, 11} also reaches the end of str since each splitted number is

    in [1, 12].  However, this is not a right split as there are two missing numbers 1 and 2, which contradicts 

    the problem assumption. Any wrong splits that can reach the end of str always has at least two missing

    numbers.

    At some point, if splitting one digit and two digits can both reach the end of str, the one digit split is 

    always the right split and it always set the final answer first.  As a result, this solution uses a boolean flag

    to ensure only the first reach of str's end updates the final answer.

     1 public class Solution {
     2     private boolean found = false;
     3     private int ans = 0;
     4     public int findMissing2(int n, String str) {
     5         boolean[] exist = new boolean[n + 1];
     6         dfs(0, n, str, exist);
     7         return ans;
     8     }
     9     
    10     private void dfs(int startIdx, int maxNum, String s, boolean[] exist) {
    11         if (startIdx >= s.length()) {
    12             if(!found){
    13                 for (int k = 1; k <= maxNum; k++) {
    14                     if (!exist[k]) {
    15                         ans = k;
    16                         break;
    17                     }
    18                 }
    19                 found = true;
    20             }
    21             return;
    22         }
    23         int sum = s.charAt(startIdx) - '0';
    24         if (sum == 0) {
    25             return;
    26         }
    27         while (sum <= maxNum) {
    28             if (!exist[sum]) {
    29                 exist[sum] = true;
    30                 dfs(startIdx + 1, maxNum, s, exist);
    31                 exist[sum] = false;
    32             }
    33             startIdx++;
    34             if (startIdx >= s.length()) {
    35                 break;
    36             }
    37             sum = sum * 10 + (s.charAt(startIdx) - '0');
    38         }
    39     }
    40 }

    Related Problems 

    Decode Ways

    Find the Missing Number

  • 相关阅读:
    第九篇 正则表达式
    第八篇、递归、装饰器
    第四篇、函数和递归
    第二篇、HTML
    nginx rewrite标签配置以及用户认证配置
    nginx location
    nginx日志配置,以及日志轮询
    nginx别名配置,状态配置,include优化
    第一篇 先用socket模拟web服务器
    第二十八篇、自定义线程池
  • 原文地址:https://www.cnblogs.com/lz87/p/7216818.html
Copyright © 2020-2023  润新知