• 边工作边刷题:70天一遍leetcode: day 94-3


    Android Unlock Patterns

    要点:

    • 本质:递归选下一个位置,返回count(规律:count的就返回count,True/False就返回True/False)
      • 递归类似permutation,所以用used记录
      • =m and <=n:

        • 类似strobogramatic III,作为recursion的结束条件。
        • 为了省事,不pass in当前len,可以减m/n:
        • 这里有技巧:如果m<=0,表示至少有一个解(如果之前的,就表示之前的,本位置不选,如果初始,就是空,符合>=0的条件),只有n<=0(不选,但是也要返回累积的),提前结束返回1
    • valid条件:used没有用并且:具体来说,
      • 一个used变量用bit可以表示9个位置的True/False,used用来记录当前dfs递归的stacktrace
      • 技巧:对于下一个位置的测试点i,j:得到used2,如果used2>used:表示i,j没有用
      • 无间隔条件:当前点和下一个测试点之间的中点有没有?因为是3X3,2个点之间差0或者1,所以可以用这个条件%2。
        • 错误理解:不是横纵都为%2==1,而是any(想想一个方向可以坐标相同)。注意跨越6格斜角是符合的。
        • 符合的是%21,不是0
    • 初始:注意recursion内loop,开始点选(1,1)是因为所有其他点都符合%2==1条件,而(1,1)这个点第三个条件满足。所以recursion内任意点都可以初始。

    https://repl.it/Cmup/1 (backtracking: beat 22.73%)
    https://repl.it/Cmup/2 (dp, beat 100%)

    • dp: dp[used][j]: all possible used of 9: 1<<9, end with j的个数。递推:
      • loop: 最外层是used,所以从less used到more used构建
      • 当前目标找到所有used里以某个i结尾,loop on last end with j, 这样可以扩展到下一个,dp[used][j]已经count过。
      • dp有很多hole是invalid的。比如used里没有i或者j
      • init: 如果只有1个键,那是1个
    # Given an Android 3x3 key lock screen and two integers m and n, where 1 ≤ m ≤ n ≤ 9, count the total number of unlock patterns of the Android lock screen, which consist of minimum of m keys and maximum n keys.
    
    # Rules for a valid pattern:
    # Each pattern must connect at least m keys and at most n keys.
    # All the keys must be distinct.
    # If the line connecting two consecutive keys in the pattern passes through any other keys, the other keys must have previously selected in the pattern. No jumps through non selected key is allowed.
    # The order of keys used matters.
    
    # Explanation:
    # | 1 | 2 | 3 |
    # | 4 | 5 | 6 |
    # | 7 | 8 | 9 |
    # Invalid move: 4 - 1 - 3 - 6 
    # Line 1 - 3 passes through key 2 which had not been selected in the pattern.
    
    # Invalid move: 4 - 1 - 9 - 2
    # Line 1 - 9 passes through key 5 which had not been selected in the pattern.
    
    # Valid move: 2 - 4 - 1 - 3 - 6
    # Line 1 - 3 is valid because it passes through key 2, which had been selected in the pattern
    
    # Valid move: 6 - 5 - 4 - 1 - 9 - 2
    # Line 1 - 9 is valid because it passes through key 5, which had been selected in the pattern.
    
    # Example:
    # Given m = 1, n = 1, return 9.
    
    # Hide Company Tags Google
    # Hide Tags Dynamic Programming Backtracking
    
    class Solution(object):
        def numberOfPatterns(self, m, n):
            """
            :type m: int
            :type n: int
            :rtype: int
            """
            def dfs(m, n, used, x, y):
                res = m<=0
                if n<=0:
                    return 1
                
                for i in xrange(3):
                    for j in xrange(3):
                        I,J,used2 = x+i,y+j,used | (1<<(i*3+j))
                        # print I,J,bin(used2)
                        if used2>used and (I%2 or J%2 or used2 & 1<<(I/2*3+J/2)):
                            res+=dfs(m-1,n-1, used2, i,j)
                return res
    
            return dfs(m, n, 0, 1, 1)
            
    sol = Solution()
    assert sol.numberOfPatterns(1,1)==9, "must be 9"                
    
    
    class Solution(object):
        def numberOfPatterns(self, m, n):
            """
            :type m: int
            :type n: int
            :rtype: int
            """
            def setused(used, i):
                return used | (1<<i) # error: not &: & is used to get bit 1, not set bit 1
            
            def unsetused(used, i):
                return used & ~(1<<i) # error: not | : set to 0
            
            def contains(used, i):
                return used & (1<<i) # error: not | : get, not set
            
            def keynumber(used):
                count = 0
                for i in xrange(9):
                    count+= (used & 1)
                    used >>= 1
                return count
            
            dp = [[0]*9 for i in xrange(1<<9)]
    
            for i in xrange(9):
                dp[setused(0, i)][i] = 1
        
            res = 0
            for used in xrange(len(dp)): # error: this is actually number
                nk = keynumber(used)
                # print bin(used), nk
                if nk>n: # error: not >= as currently testing used
                    continue
    
                for i in xrange(9):
                    if not contains(used, i):
                        continue
                    
                    for j in xrange(9):
                        if i==j or not contains(used, j): # error: not (contains) as testing used
                            continue
                        
                        x0, y0 = i/3, i%3
                        x1, y1 = j/3, j%3
                    
                        I,J = x0+x1, y0+y1
                        if I%2 or J%2 or contains(used, I/2*3+J/2):
                            # print bin(used), j
                            dp[used][i]+=dp[unsetused(used, i)][j]
                        
                    if m<=nk<=n: # error: 
                        # print bin(used), nk, i, dp[used][i]
                        res+=dp[used][i]
            return res
                    
    
  • 相关阅读:
    node03- FS内置模块
    node03- CommonJS
    删除当前目录下的所有文件夹和文件
    解决 idea 项目中Error:java: 无效的标记
    Raid0,Raid1,Raid5,Raid10 总结
    Tcpdump命令
    ClassNotFoundException 和 NoClassDefFoundError 区别
    Dart-List里面常用的属性和方法
    CSS实现等分布局的4种方式
    iOS项目添加CocoaPods
  • 原文地址:https://www.cnblogs.com/absolute/p/5815860.html
Copyright © 2020-2023  润新知