1. 程式人生 > >[LintCode] Find the Missing Number II

[LintCode] Find the Missing Number II

you flag discus body ted rst related chan boolean

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

[LintCode] Find the Missing Number II