1. 程式人生 > >Leetcode 753. Cracking the Safe

Leetcode 753. Cracking the Safe

Problem:

There is a box protected by a password. The password is n digits, where each letter can be one of the first k digits 0, 1, ..., k-1.

You can keep inputting the password, the password will automatically be matched against the last n digits entered.

For example, assuming the password is "345"

, I can open it when I type "012345", but I enter a total of 6 digits.

Please return any string of minimum length that is guaranteed to open the box after the entire string is inputted.

Example 1:

Input: n = 1, k = 2
Output: "01"
Note: "10" will be accepted too.

Example 2:

Input:
n = 2, k = 2 Output: "00110" Note: "01100", "10011", "11001" will be accepted too.

Note:

  1. n will be in the range [1, 4].
  2. k will be in the range [1, 10].
  3. k^n will be at most 4096.

 

Solution:

  這道題thumb down的次數大於thumb up的次數,可見這道題不是很好。對於這道題,總共有k^n

種可能的排列,我們現在要把它組合成一個長度為k^n+n-1的字串,使得所有的排列都是這個字串的子串。對於這個問題,常規思路是用backtrace,其時間複雜度為k^(k^n),時間複雜度相當高。而答案使用了一種貪心演算法,對於下一個要新增的字元s[i],從大到小找到s[i-n+1]到s[i]的未使用過的子串,比如00之後,從1到0找到第一個未使用的子串01,將1新增到末尾變為001。雖然這個演算法可行,但對於這道題來說,我們很難找到一種從暴力解法到可優化解法的思考過程,對於這個演算法是否可行我們也沒有辦法證明。因此,對於這道題,我更多的覺得只要記住這種解法即可。

Code:

 

 1 class Solution {
 2 public:
 3     string crackSafe(int n, int k) {
 4         string res = string(n, '0');
 5         unordered_set<string> visited{{res}};
 6         for (int i = 0; i < pow(k, n); ++i) {
 7             string pre = res.substr(res.size() - n + 1, n - 1);
 8             for (int j = k - 1; j >= 0; --j) {
 9                 string cur = pre + to_string(j);
10                 if (!visited.count(cur)) {
11                     visited.insert(cur);
12                     res += to_string(j);
13                     break;
14                 }
15             }
16         }
17         return res;
18     }
19 };