Leetcode: Android Unlock Patterns

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.

我自己的backtracking做法

最开始把cur设置为一个dummy value 0

 1 public class Solution {
 2     int num = 0;
 3     public int numberOfPatterns(int m, int n) {
 4         for (int len=m; len<=n; len++) {
 5             HashSet<Integer> visited = new HashSet<Integer>();
 6             count(visited, 0, 0, len);
 7         }
 8         return num;
 9     }
10
11     public void count(HashSet<Integer> visited, int cur, int pos, int len) {
12         if (pos == len) {
13             num++;
14             return;
15         }
16         for (int elem=1; elem<=9; elem++) {
17             if (visited.contains(elem)) continue;
18             if (cur == 1) {
19                 if (elem==3 && !visited.contains(2)) continue;
20                 if (elem==7 && !visited.contains(4)) continue;
21                 if (elem==9 && !visited.contains(5)) continue;
22             }
23             else if (cur == 2) {
24                 if (elem == 8 && !visited.contains(5)) continue;
25             }
26             else if (cur == 3) {
27                 if (elem==1 && !visited.contains(2)) continue;
28                 if (elem==7 && !visited.contains(5)) continue;
29                 if (elem==9 && !visited.contains(6)) continue;
30             }
31             else if (cur == 4) {
32                 if (elem == 6 && !visited.contains(5)) continue;
33             }
34             else if (cur == 6) {
35                 if (elem == 4 && !visited.contains(5)) continue;
36             }
37             else if (cur == 7) {
38                 if (elem==1 && !visited.contains(4)) continue;
39                 if (elem==3 && !visited.contains(5)) continue;
40                 if (elem==9 && !visited.contains(8)) continue;
41             }
42             else if (cur == 8) {
43                 if (elem==2 && !visited.contains(5)) continue;
44             }
45             else if (cur == 9) {
46                 if (elem==1 && !visited.contains(5)) continue;
47                 if (elem==3 && !visited.contains(6)) continue;
48                 if (elem==7 && !visited.contains(8)) continue;
49             }
50             visited.add(elem);
51             count(visited, elem, pos+1, len);
52             visited.remove(elem);
53         }
54     }
55 }

最好的DFS with Optimization beat 97%: https://discuss.leetcode.com/topic/46260/java-dfs-solution-with-clear-explanations-and-optimization-beats-97-61-12ms

Use an matrix to store the corssed number for each possible move and use DFS to find out all patterns.

The optimization idea is that 1,3,7,9 are symmetric, 2,4,6,8 are also symmetric. Hence we only calculate one among each group and multiply by 4.

 1 public class Solution {
 2     // cur: the current position
 3     // remain: the steps remaining
 4     int DFS(boolean vis[], int[][] skip, int cur, int remain) {
 5         if(remain < 0) return 0;
 6         if(remain == 0) return 1;
 7         vis[cur] = true;
 8         int rst = 0;
 9         for(int i = 1; i <= 9; ++i) {
10             // If vis[i] is not visited and (two numbers are adjacent or skip number is already visited)
11             if(!vis[i] && (skip[cur][i] == 0 || (vis[skip[cur][i]]))) {
12                 rst += DFS(vis, skip, i, remain - 1);
13             }
14         }
15         vis[cur] = false;
16         return rst;
17     }
18
19     public int numberOfPatterns(int m, int n) {
20         // Skip array represents number to skip between two pairs
21         int skip[][] = new int[10][10];
22         skip[1][3] = skip[3][1] = 2;
23         skip[1][7] = skip[7][1] = 4;
24         skip[3][9] = skip[9][3] = 6;
25         skip[7][9] = skip[9][7] = 8;
26         skip[1][9] = skip[9][1] = skip[2][8] = skip[8][2] = skip[3][7] = skip[7][3] = skip[4][6] = skip[6][4] = 5;
27         boolean vis[] = new boolean[10];
28         int rst = 0;
29         // DFS search each length from m to n
30         for(int i = m; i <= n; ++i) {
31             rst += DFS(vis, skip, 1, i - 1) * 4;    // 1, 3, 7, 9 are symmetric
32             rst += DFS(vis, skip, 2, i - 1) * 4;    // 2, 4, 6, 8 are symmetric
33             rst += DFS(vis, skip, 5, i - 1);        // 5
34         }
35         return rst;
36     }
37 }
时间: 2024-10-23 17:59:21

Leetcode: Android Unlock Patterns的相关文章

[LeetCode] Android Unlock Patterns 安卓解锁模式

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 m

[Swift]LeetCode351. 安卓解锁模式 $ Android Unlock Patterns

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 m

Android Unlock Patterns

public class Solution { private boolean[][] visited = new boolean[3][3]; private int m; private int n; public int numberOfPatterns(int m, int n) { if (n == 0 || m > n) { return 0; } int result = 0; this.m = m; this.n = n; for (int i = 0; i < 3; i++)

Android Design Patterns

出版时间:2013 下载地址:百度网盘 内容简介: Master the challenges of Android user interface development with these sample patterns With Android 4, Google brings the full power of its Android OS to both smartphone and tablet computing. Designing effective user interfac

Android Performance Patterns S01E02 - Understanding Overdraw

Overdraw:过度绘制是一个术语,用来描述组件在屏幕某个像素上面绘制大于一次. 例如,如果我们有一堆叠放的UI卡片,用户可见的上层卡片遮盖了下层卡片的大部分.这也意味着大量时间花费在绘制不可见的下层卡片.如果每次都花费大量时间,用以绘制不可见的部分,将会导致GPU性能严重浪费的问题. Modern布局给了我们美观的设计,但是也给开发者带来了上述的问题. 为了最大限度提升App的性能,开发者需要最大限度减少Overdraw. 幸运的是,在Android设备上很容易查看APP Overdraw造

关于youtube上Android Performance Patterns的总结(部分)

1.熟悉android studio关于Logcat,Memory,CPU,GPU,Network分析窗口的使用.一旦你配置的内存突然下降,那么应该是GC在发挥作用.这些垃圾收集活动通常不会太大影响性能,但是短时间内频繁的出现,会迅速消耗帧时间,还是会导致性能问题的. 2.内存泄露:指的是应用不再使用的对象,但是垃圾收集没有把它们辨认出来.结果是它们一直留在你的内存里. android运行环境中的内存堆: android runtime内存堆被有效的划分为不同的区块,根据配置的类型,还根据系统为

Android Performance Patterns S01

S01E02 Rendering performance 渲染性能问题 渲染性能问题是app开发的最常见问题. 系统每隔大约16ms(1/60秒)尝试绘制Activity,如果无法每隔16ms成功绘制出新的图,则会出现掉帧的现象.也就是说,APP每16ms要运行结束所有刷新屏幕的逻辑,屏幕才能达到每秒60帧. 如下图: 用户很容易察觉掉帧引起的卡顿问题,如拖动列表卡顿.输入法输入卡顿.引起卡顿的原因可能有多种,如: View结构的较大部分的重新绘制花费过多时间(CPU周期,CPU cycles)

Android Performance Patterns S01E03 - Why 60fps?

在注重App性能的领域,60fps和16ms(毫秒)是经常提及的概念.但是,为什么数字是60和16呢? 这些技术细节是与硬件相关的,——与人眼有关. 人眼与照相机的工作原理不同,不会发送现实世界的快照图片至人脑,供人来识别现实世界.大脑不断地处理眼睛发送给它的视觉信号,所以对于我们大脑来说,并没有帧或快照的概念,我们对运动的概念受到静止帧的影响很大.当静止图像的轮换显示足够快时,我们可以成功地骗过人脑,让其误感知到并未存在的运动. 重要的是,我们切换静止图像的速度,对我们感知的运动的流畅度有巨大

Android Performance Patterns S01E02 - Rendering performance

S01E02 Rendering performance 渲染性能问题 渲染性能问题是app开发的最常见问题. 系统每隔大约16ms(1/60秒)尝试绘制Activity,如果无法每隔16ms成功绘制出新的图,则会出现掉帧的现象.也就是说,APP每16ms要运行结束所有刷新屏幕的逻辑,屏幕才能达到每秒60帧. 如下图: 用户很容易察觉掉帧引起的卡顿问题,如拖动列表卡顿.输入法输入卡顿.引起卡顿的原因可能有多种,如: View结构的较大部分的重新绘制花费过多时间(CPU周期,CPU cycles)