代码改变世界

[LeetCode] 753. Cracking the Safe_Hard tag: DFS, backtracking

2021-08-19 10:11  Johnson_强生仔仔  阅读(31)  评论(0编辑  收藏  举报

There is a safe protected by a password. The password is a sequence of n digits where each digit can be in the range [0, k - 1].

The safe has a peculiar way of checking the password. When you enter in a sequence, it checks the most recent n digits that were entered each time you type a digit.

  • For example, the correct password is "345" and you enter in "012345":
    • After typing 0, the most recent 3 digits is "0", which is incorrect.
    • After typing 1, the most recent 3 digits is "01", which is incorrect.
    • After typing 2, the most recent 3 digits is "012", which is incorrect.
    • After typing 3, the most recent 3 digits is "123", which is incorrect.
    • After typing 4, the most recent 3 digits is "234", which is incorrect.
    • After typing 5, the most recent 3 digits is "345", which is correct and the safe unlocks.

Return any string of minimum length that will unlock the safe at some point of entering it.

 

Example 1:

Input: n = 1, k = 2
Output: "10"
Explanation: The password is a single digit, so enter each digit. "01" would also unlock the safe.

Example 2:

Input: n = 2, k = 2
Output: "01100"
Explanation: For each possible password:
- "00" is typed in starting from the 4th digit.
- "01" is typed in starting from the 1st digit.
- "10" is typed in starting from the 3rd digit.
- "11" is typed in starting from the 2nd digit.
Thus "01100" will unlock the safe. "01100", "10011", and "11001" would also unlock the safe.

 

Constraints:

  • 1 <= n <= 4
  • 1 <= k <= 10
  • 1 <= kn <= 4096

 

Ideas:

1. 要有k ^ n 种情况,如果要最短的话,那么就让前面n - 1个string作为prefix,依次在后面加上一个string,其实不知道为啥这样就能保证肯定是有,说是有euler path, 有空再看看

2. 从 ans = "0" * n 开始,依次以ans[-n + 1:]作为prefix然后来看是否可以加入str(i)

3. 再用backtracking来将所有的可能性全部弄出来; note(这里返回ans, 如果ans只是作为parameter来传进去的话,在function里面改变ans,不会改变原ans)

4. 另外需要注意的是当n == 1 的edge case

 

Code:

class Solution:
    def crackSafe(self, n: int, k: int) -> str:
        ans = "0" * n
        visited = set([ans])
        times = k ** n
        return self.dfs(ans, visited, times, n, k)
    
    def dfs(self, ans, visited, times, n, k):
        if len(visited) == times:
            return ans
        lastDigits = ans[-n + 1:]
        for i in range(k):
            newDigits = lastDigits + str(i) if n != 1 else str(i)
            if newDigits not in visited:
                visited.add(newDigits)
                ans += str(i)
                temp = self.dfs(ans, visited, times, n, k)
                if temp:
                    return temp
                visited.remove(newDigits)
                ans = ans[:-1]