Leetcode——安卓系统手势解锁(九宫格)
Posted Yawn,
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Leetcode——安卓系统手势解锁(九宫格)相关的知识,希望对你有一定的参考价值。
1. 安卓系统手势解锁
(1)回溯(模版方法)
// 至少 需要经过 m 个点,但是 不超过 n 个点的。
class Solution {
int count = 0;
public int numberOfPatterns(int m, int n) {
if (m > n)
return 0;
//对于每个路径长度进行回溯
for (int i = m; i <= n; i++) {
HashSet<Integer> inPath = new HashSet<>();
Deque<Integer> path = new LinkedList<>();
trackBacking(0, i, path, inPath);
}
/* 考虑对称,对称可以节省计算
numberOfPatterns(0, m, n, visited, 1);
numberOfPatterns(1, m, n, visited, 1);
count *= 4;
numberOfPatterns(4, m, n, visited, 1);
*/
return count;
}
/*
* @param cur 当前的点
* @param len 路径长度
* @param path 路径
* @param inPath 路径中已存在的点
*/
private void trackBacking(int cur, int len, Deque<Integer> path, HashSet<Integer> inPath) {
if (path.size() == len) {
count++;
return;
}
for (int tar = 1; tar <= 9; tar++) {
//目标点是当前点或者已经在路径内
if (tar == cur || inPath.contains(tar))
continue;
//计算两个点之间有没有存在的点,如果没有,返回null
Integer pointBetween = getPointBetween(cur, tar);
//当前点和目标点之间有点,并且不在已访问的路径内
if (pointBetween != null && !inPath.contains(pointBetween))
continue;
path.addLast(tar);
inPath.add(tar);
trackBacking(tar, len, path, inPath);
path.pollLast();
inPath.remove(tar);
}
}
//计算两个点之间有没有存在的点,如果没有,返回null
public Integer getPointBetween(int startPoint, int targetPoint) {
if (startPoint == -1)
return null;
int[] startP = getPosition(startPoint);
int[] targetP = getPosition(targetPoint);
int diff = Math.abs(startP[0] - targetP[0]) + Math.abs(startP[1] - targetP[1]);
//两点之间无其他点,之间相连
if (diff == 1)
return null;
//两点之间有一个点
else if (diff == 2) {
//同行相隔一个点:1,3 ; 4,6 ; 7,9 等
if (startP[0] == targetP[0])
return 3 * startP[0] + Math.min(startP[1], targetP[1]) + 2;
//同列相隔一个点:1,7 ; 2,8 ; 3,9 等
else if (startP[1] == targetP[1])
return 3 * (Math.min(startP[0], targetP[0]) + 1) + startP[1] + 1;
//其他情况都不存在
else
return null;
}
//两点之间为4,只有中间节点为5时有效
else if (diff == 4) {
if (startP[0] + targetP[0] == 2 && startP[1] + targetP[1] == 2) {
return 5;
}
}
//其他情况比如:2,9相连时,相当于中间没有节点
return null;
}
//存储 1 - 9 每个节点的位置
public int[] getPosition(int point) {
switch (point) {
case 1:
return new int[]{0, 0};
case 2:
return new int[]{0, 1};
case 3:
return new int[]{0, 2};
case 4:
return new int[]{1, 0};
case 5:
return new int[]{1, 1};
case 6:
return new int[]{1, 2};
case 7:
return new int[]{2, 0};
case 8:
return new int[]{2, 1};
case 9:
return new int[]{2, 2};
default:
return new int[]{-1, -1};
}
}
}
(2)回溯(简洁写法)
- 矩形的遍历搜索
- 本题比较特殊,方向不再是上下左右,还有四个对角线,仔细观察示例,发现还有与当前位置偏移(1,2)的也算
- 如果中间有已经访问点,仍可以连接其后的点,实际上就是在当前方向遇到已访问点,遍历其后面的点是否未访问,未访问则选择这个点
class Solution {
int count;
// 上下及对角线、斜线,总共16个组合
int[][] direction = {{1,0}, {-1,0}, {0,1}, {0,-1}, {1,1}, {-1,-1}, {1,-1}, {-1,1},
{1,2}, {2,1}, {1,-2},{-2,-1}, {-1,2}, {2,-1},{-1,-2}, {-2,1}};
public int numberOfPatterns(int m, int n) {
// 判断是否访问过
boolean[] visited = new boolean[9];
// 9个起点
for (int i = 0; i < 9; i++) {
numberOfPatterns(i, m, n, visited, 1);
}
return count;
}
private void numberOfPatterns(int start, int m, int n, boolean[] visited, int num) {
//已经遍历过,或者节点超过n个
if (visited[start] || num > n)
return;
//符合条件的节点,count++
if (num >= m && num <= n)
count++;
// 试探
visited[start] = true;
//例如2:在0行,1列 : 2/3 = 0, 2 % 3 = 1, 所以这里行用 / , 列用%
int row = start / 3, col = start % 3;
for (int[] dir : direction) {
int x = row + dir[0], y = col + dir[1];
// 新坐标非法
if (x < 0 || x > 2 || y < 0 || y > 2)
continue;
// 如果新坐标被访问过,根据题意,在该方向继续查找,直到找到一个未访问的有效点
while (visited[x * 3 + y]) {
x += dir[0];
y += dir[1];
// 新坐标非法
if (x < 0 || x > 2 || y < 0 || y > 2)
break;
}
// 新坐标非法
if (x < 0 || x > 2 || y < 0 || y > 2)
continue;
numberOfPatterns(3 * x + y, m, n, visited, num + 1);
}
// 回溯
visited[start] = false;
}
}
以上是关于Leetcode——安卓系统手势解锁(九宫格)的主要内容,如果未能解决你的问题,请参考以下文章