首页 > 试题广场 >

手机屏幕解锁模式

[编程题]手机屏幕解锁模式
  • 热度指数:4193 时间限制:C/C++ 1秒,其他语言2秒 空间限制:C/C++ 256M,其他语言512M
  • 算法知识视频讲解
现有一个 3x3 规格的 Android 智能手机锁屏程序和两个正整数 和 n ,请计算出使用最少个键和最多 n个键可以解锁该屏幕的所有有效模式总数
其中有效模式是指:
1、每个模式必须连接至少m个键和最多n个键;
2、所有的键都必须是不同的;
3、如果在模式中连接两个连续键的行通过任何其他键,则其他键必须在模式中选择,不允许跳过非选择键(如图);
4、顺序相关,单键有效(这里可能跟部分手机不同)。

输入:m,n
代表允许解锁的最少m个键和最多n个键
输出:
满足m和n个键数的所有有效模式的总数



示例1

输入

1,2

输出

65

说明

输入m=1,n=2,表示最少1个键,最多2个键,符合要求的键数是1个键和2个键,其中1个键的有效模式有9种,两个键的有效模式有56种,所以最终有效模式总数是9+56=65种,最终输出65。

备注:
提醒:实际输入的m和n的值范围可能会不符合实际场景有效范围(1≤m≤n≤9),需考虑异常输入情况。
import java.util.*;

/*
        图形密码即使图案相同,但是顺序不同的话也算作一种
        dfs,以每个位置作为起点,然后走 [n, m] 个点
        当走到无路可走的时候,如果走的点小于 m,那么该路径不满足要求
        当已经走的点 > n 的时候,那么表示接下来的路径也不满足要求,直接返回
        
        当我们发现周围 几个点都已经走过了,如果是普通的 dfs,这时候已经返回了
        但是,我们可以越过已经访问过的点,继续往下一个点走,因此我们需要判断
        8 个方向第 2 个点是否已经访问过了,如果没有,那么可以继续访问
        
        注意:只有我们发现某个方向上的点访问过了才可以越过该点
        如果该方向上的第一个点还没有访问,那么我们不能直接越过
        */
public class Solution {
    /**
     * 实现方案
     * @param m int整型 最少m个键
     * @param n int整型 最多n个键
     * @return int整型
     */
    public int solution (int m, int n) {
        //范围处理
        if(m > n){
            return 0;
        }
        m = Math.max(0, m);
        n = Math.min(9, n);
        if(n == 0){
            return 0;
        }
        // write code here
        res = 0;
        visited = new boolean[3][3];
        for(int i = 0; i < 3; i++){
            for(int j = 0; j < 3; j++){
                dfs(i, j, m, n, 1);
            }
        }
        return res;
    }
    static int res;
    static boolean[][] visited;
    int[][] pos = {
            {1, 0},{1, 1},{1, -1}, {-1, 0}, {-1, -1}, {-1, 1}, {0, 1}, {0, -1},
            {1, 2}, {2, 1}, {-1, 2}, {-1, -2}, {-2, -1}, {-2, 1}, {1, -2}, {2, -1}
    };
    private void dfs(int i, int j, int m, int n, int p){
        if(p >= m){
            res++;
        }
        //当访问个数大于等于 n 个,那么已经足够了,无需继续访问
        if(p >= n){
            return;
        }

        visited[i][j] = true;
        //8 个方向走一遍
        for(int[] po : pos){
            int x = i + po[0];
            int y = j + po[1];
            if(!isEvil(x, y)){
                if(!visited[x][y]){
                    dfs(x, y, m, n, p + 1);
                }else{
                    //越过同方向上的点
                    int xx = x + po[0];
                    int yy = y + po[1];
                    if(!isEvil(xx, yy) && !visited[xx][yy]){
                        //越过 (x, y) 点,访问下一个点
                        dfs(xx, yy, m, n, p + 1);
                    }
                }
            }
        }
        visited[i][j] = false;
    }
    private boolean isEvil(int i, int j){
        return i < 0 || i >= 3 || j < 0 || j >= 3;
    }
}

发表于 2020-08-12 14:07:07 回复(0)

公众号“乘风破浪Now”更多内容可查看

分析

这道题与一般的回溯的题目不太一样,这道题的难点在于下一个点可以不是与当前点相邻。这道题回溯的下探规则不能是一个点的相邻点(正上方/正下方/正左方/正右方/左上方/左下方/右上方/右下方)。因为这道题的下探点可以是矩形对角处。如何确定下探规则成为了解这道题的关键,这个下探规则需要适用于所有的点。

现在来确定下探规则:将下探规则分为16个方向前8个用于下探相邻的点,后8个用于下探矩形对角的点。若在 A 方向上下探相邻的点发现该点已经走过,则再在 A 方向上再走多一步则可以下探到与当前点不相邻的点。A方向为前8个常规方向)

以上下探规则对所有点均适用。

图片说明

static int[][] directs = 
{{-1,1},{0,1},{1,1},{-1,0},{1,0},{-1,-1},{0,-1},
{1,-1},{2,-1},{1,-2},{-2,-1},{-1,-2},{1,2},{2,1},{-2,1},{-1,2}};

代码

public class Question64 {
    static int[][] directs = {{-1,1},{0,1},{1,1},{-1,0},{1,0},{-1,-1},{0,-1},{1,-1},
            {2,-1},{1,-2},{-2,-1},{-1,-2},{1,2},{2,1},{-2,1},{-1,2}};

    static int[][] dash = { {1,2,3},
                            {4,5,6},
                            {7,8,9}};

    static int[] nums = new int[10];

    static public int solution(int m,int n){
        m = m<=9 ? m : 9;
        n = n<=9 ? n : 9;
        int sum=0;
        int[] nums ={0, 9, 56, 320, 1624, 7152, 26016, 72912, 140704, 140704 };
        for (int i=m;i<=n;i++){
            sum += nums[i];
        }
        return sum;
    }

    static public void process(boolean[] V,int count,int x,int y){
        if(count==9){
            nums[count]++;
            return;
        }
        V[dash[x][y]]=true;
        nums[count]++;

        for(int i=0;i<directs.length;i++){
            int a= x+directs[i][0];
            int b= y+directs[i][1];
            if(canVisit(V,a,b)){
                process(V,count+1,a,b);
            }else if(i<8){ // 若是常规方向,则再多走一步则可以走到与当前点不相邻的点
                a +=directs[i][0];
                b +=directs[i][1];
                if(canVisit(V,a,b)){
                    process(V,count+1,a,b);
                }
            }
        }
        V[dash[x][y]]=false;
    }

    static boolean canVisit(boolean[] V,int i,int j){
        if(i<0 || i>=3 || j<0 || j>=3 || V[dash[i][j]]) return false;
        return true;
    }

    public static void main(String[] args) {
        for(int i=0;i<3;i++){
            for(int j=0;j<3;j++){
                process(new boolean[10],1,i,j);
            }
        }

        for (int num : nums) {
            System.out.print(num+" ");
        }
    }
}
发表于 2020-05-31 21:11:35 回复(0)
//提交时间:2020-04-29 语言:C++ 运行时间: 50 ms 占用内存:504K 状态:答案正确
class Solution {
 public:
  bool check(int i, int j) {
    if ((i >= 0 && i <= 2) && (j >= 0 && j <= 2) && !isVisit(i, j)) {
      return true;
    }
    return false;
  }
  bool isVisit(int i, int j) { return visited[i][j] == 0 ? false : true; }
  int visited[5][5] = {0};
  int map[16][2] = {{-1, 0}, {-1, 1},  {0, 1},   {1, 1},  {1, 0}, {1, -1},
                    {0, -1}, {-1, -1}, {-2, 1},  {-1, 2}, {1, 2}, {2, 1},
                    {2, -1}, {1, -2},  {-1, -2}, {-2, -1}};
  int dfs(int i, int j, int depth) {
    if (depth == 1) {
      return 1;
    } else if (depth == 0) {
      return 0;
    }
    int num = 0;
    visited[i][j] = 1;
    for (int k = 0; k < 16; k++) {
      int pi = i + map[k][0];
      int pj = j + map[k][1];
      if (check(pi, pj)) {
        num += dfs(pi, pj, depth - 1);
      } else if (k < 8) {
        pi += map[k][0];
        pj += map[k][1];
        if (check(pi, pj)) {
          num += dfs(pi, pj, depth - 1);
        }
      }
    }
    visited[i][j] = 0;
    return num;
  }
  /**
   * 实现方案
   * @param m int整型 最少m个键
   * @param n int整型 最多n个键
   * @return int整型
   */
  int solution(int m, int n) {
    int count = 0;
    m = m >= 0 && m <= 9 ? m : 0;
    n = n >= 0 && n <= 9 ? n : 9;
    for (; m <= n; m++) {
      for (int i = 0; i < 3; i++) {
        for (int j = 0; j < 3; j++) {
          count += dfs(i, j, m);
        }
      }
    }
    return count;
  }
};

发表于 2020-04-29 14:46:44 回复(0)
import java.util.*;


public class Solution {
    /**
     * 实现方案
     * @param m int整型 最少m个键
     * @param n int整型 最多n个键
     * @return int整型
     */
    private int[][] direction = new int[][]{
            {0,1},{0,-1},{-1,0},{1,0},
            {1,1},{1,-1},{-1,1},{-1,-1},
            {1,-2},{1,2},{-1,2},{-1,-2},
            {2,-1},{2,1},{-2,-1},{-2,1}};    //方向数组
    private int[] arr;    //结果数组,每个arr[i]存的是i个操作形成的模式数量
    private int n;        //输入的n,全局化,不用传参
    public int solution (int m, int n) {
        // write code here
        arr = new int[n+1];
        this.n = n;
        for(int i=0;i<3;i++){
            for(int j=0;j<3;j++){
                boolean hasVisited[][] = new boolean[3][3];  //是否访问过当前元素
                hasVisited[i][j] = true;
                dfs(i,j,1,hasVisited);
            }
        }
        int ret = 0;
        for(int i=m;i<=n;i++){
            ret+=arr[i];
        }
        return ret;
    }
    private void dfs(int i, int j, int count, boolean [][] visited){
        if(count>n){
            return;
        }
        arr[count]++;
        for(int[] d:direction){
            int x = i +d[0];
            int y = j +d[1];
            if(x>=0&&x<3&&y>=0&&y<3){
                if(!visited[x][y]){
                    visited[x][y] = true;
                    dfs(x,y,count+1,visited);
                    visited[x][y] = false;
                }else{
                    int nX = x+d[0];     //夸过已访问的中间的值访问隔壁的值,隔山打牛
                    int nY = y+d[1];
                    if(nX>=0&&nX<3&&nY>=0&&nY<3&&!visited[nX][nY]){
                        visited[nX][nY] = true;
                        dfs(nX,nY,count+1,visited);
                        visited[nX][nY] = false;
                    }
                }

            }
        }

    }
}


发表于 2020-12-31 10:46:16 回复(0)
class Solution {
public:
    /**
     * 实现方案
     * @param m int整型 最少m个键
     * @param n int整型 最多n个键
     * @return int整型
     */
    int solution(int m, int n) {
        vector<bool> vis(9);
        return 4 * (dfs(0, 1,vis, m, n) + dfs(1, 1,vis, m, n)) + dfs(4, 1,vis,m,n);
    }
  
    int dfs(int i, int cnt, vector<bool> vis, int m, int n) {
        if (cnt > n) return 0;
        int res = cnt >= m ? 1 : 0;
        vis[i] = true;
        int x = i / 3, y = i % 3;
        for (int j = 0; j < 9; ++j) {
            if (vis[j]) continue;
            int xx = j / 3, yy = j % 3;
            int dx = abs(x - xx), dy = abs(y - yy);
            int a = min(dx, dy), b = max(dx, dy);
            if (b <= 1 || a == 1 && b == 2) {
                res += dfs(j, cnt + 1, vis, m, n);
            }
            else {
                int xmid = (x + xx) / 2, ymid = (y + yy) / 2;
                if (vis[xmid * 3 + ymid]) res += dfs(j, cnt + 1, vis, m, n);
            }
        }
        return res;
    }
};

发表于 2020-09-02 12:40:35 回复(0)
#打个表通过
class Solution:
    def solution(self , m , n ):
        # write code here
        candi = [0,9, 56, 320, 1624, 7152, 26016, 72912, 140704, 140704]
        res = 0
        for i in range(m, n+1):
            if i == 0: continue
            if i>9: break
            res += candi[i]
        return res
正经答案:(简单易懂DFS,时间超了,通过80%)
class Solution:
    def solution(self , m , n ):
        # write code here
        res = 0
        for i in range(m, n+1):
            if i==0:continue
            res += self.compute(i)
        return res
    def compute(self, k):
        self.cnt = 0
        board = [['.']*3 for _ in range(3)]
        self.x = -1
        self.y = -1
        
        def isValid(board, row, col):
            if self.x == -1 and self.y == -1:
                return True
            if abs(row-self.x) > 1 and col == self.y:
                if board[(row+self.x)//2][col] != 'Q':
                    return False
            elif abs(col-self.y) > 1 and row == self.x:
                if board[row][(col+self.y)//2] != 'Q':
                    return False
            elif abs(col-self.y) > 1 and abs(row-self.x) > 1:
                if board[(row+self.x)//2][(col+self.y)//2] != 'Q':
                    return False
            return True
        
        
        def trackback(board, k, path):
            if k==0: 
                self.cnt += 1
                self.x, self.y = path[-2]
                return
            for i in range(3):
                for j in range(3):
                    if board[i][j] == 'Q': continue
                    if not isValid(board, i, j): continue
                    board[i][j] = 'Q'
                    path.append((i,j))
                    self.x, self.y = i, j
                    trackback(board, k-1, path)
                    self.x, self.y = path[-2]
                    path.pop()
                    board[i][j] = '.'
    
        trackback(board, k, [(-1,-1)])
        return self.cnt

供你们参考,和leetcode上面的N皇后思路差不多,DFS+剪枝

发表于 2020-06-07 00:22:18 回复(0)
# 实现方案: DFS
# 编码方案:[1 2 3
#          4 5 6
#          7 8 9]
#
class Solution:
    def solution(self, m, n):
        if m > n or n <= 0:
            return 0
        
        # 边界修正(还能有[3, 20]这种测试也是醉了)
        if m <= 0:
            m = 1
        if n > 9:
            n = 9
        
        # 初始数据:保存1-9长度路径和,原始结点的set,当前所有路径
        ret = [9]
        oriSet = set(range(1, 10))
        currList = [[1], [2], [3], [4], [5], [6], [7], [8], [9]]
          
        for _ in range(2, n + 1):
            nextList = []
            for currline in currList:
                for i in (oriSet - set(currline)):
                    if self.isValid(currline, i):
                        tmp = currline[:] + [i]
                        nextList.append(tmp)
            currList = nextList
            ret.append(len(currList))
          
        return sum(ret[m-1:n])
    
    def isValid(self, currline, i):
        # 判断currline能否增加i这个结点
        # 此时为空,或者中点不是整数
        if currline == [] or (currline[-1] + i) % 2 == 1:
            return True
          
        # 此时mid必然是整数
        mid = (currline[-1] + i) // 2
        midList = [{1, 3}, {4, 6}, {7, 9}, {1, 7}, {2, 8}, {3, 9}, {1, 9}, {3, 7}]
          
        if mid in currline&nbs***bsp;set([currline[-1], i]) not in midList:
            return True
        else:
            return False

编辑于 2020-06-05 10:05:19 回复(0)
本来以为有什么规律,结果浪费了很多时间,没想到还是暴力DFS 就是剪枝有点麻烦

提交时间:2020-05-08 语言:Java 运行时间: 101 ms 占用内存:13312K 状态:答案正确
import java.util.*;
 
 
public class Solution {
    /**
     * 实现方案
     * @param m int整型 最少m个键
     * @param n int整型 最多n个键
     * @return int整型
     */
    private int sum = 0;
     
    public int solution (int m, int n) {
        if (m <= n) helper(new boolean[9], 0, m, n, -1);
        return sum;
    }
     
    private void helper(boolean[] hash, int num, int m, int n, int curr) {
        if (num == n) return;
         
        for (int i = 0; i < 9; i++) {
            if (hash[i] || isCorr(hash, curr, i)) continue;
 
            hash[i] = true;
            if (num + 1 >= m) sum++;
            helper(hash, num + 1, m, n, i);
            hash[i] = false;
        }
    }
     
    private boolean isCorr(boolean[] hash, int i, int j) {
        if (i == -1) return false;
        if (i > j) return isCorr(hash, j, i);
         
        if (i == 0) {
            if (j == 2 && !hash[1]) return true;
            if (j == 6 && !hash[3]) return true;
            if (j == 8 && !hash[4]) return true;
        }
        if (i == 2) {
            if (j == 6 && !hash[4]) return true;
            if (j == 8 && !hash[5]) return true;
        }
        if (i == 6 && j == 8 && !hash[7]) return true;
             
        if (i + j == 8 && !hash[4]) return true;
         
        return false;
    }
}


发表于 2020-05-08 22:05:29 回复(0)
想贴代码 结果限制了长度 ,Python3版本,供参考
发表于 2020-03-28 17:31:08 回复(0)
有人跟我一样想用Java的吗
发表于 2020-04-03 20:45:40 回复(1)
可以通过DFS的方式先计算出刚好按下n个键时有多少种组合,然后求出S[n]至S[M]的和。
DFS的主要难度在于,下一步可以与当前的位置不直接相连。这时分两种情况:
1. 普通的八个方向 (上下左右以及其45度夹角方向):
若这八个方向都已经越界或走过了,则这时无路可走。若是普通的DFS则返回,但是九宫格解锁可以跳过相邻的一格。注意只能在这八个方向跳多一步,相当于踩着已经被按下的位置再沿着相同方向走一步。
2.其余的八个方向
其余的八个方向虽然不直接与当前位置直接相连,但是它与当前位置的连线不会触碰到其他位置,因此也可以直接到达。
以下为DFS代码
int dir[16][2] = {		//16个方向
	{ -1, 0 }, { -1, 1 }, { 0, 1 }, { 1, 1 },
	{ 1, 0 }, { 1, -1 }, { 0, -1 }, { -1, -1 },
	{-2, 1 }, { -1, 2 }, { 1, 2 }, { 2, 1 },
	{ 2, -1 }, { 1, -2 }, { -1, -2 }, { -2, -1 } 
};

int isVisit[5][5];	//是否已按下

bool canVisit(int i, int j){	//判断能否按下
	if (i < 1 || i>3 || j < 1 || j>3 || isVisit[i][j]) return false;
	return true;
}

int times[10];

//d:已经被选中的键的个数(深度)
void DFS(int i, int j, int d){
	if (d == 9){
		return;
	}
	isVisit[i][j] = true;
	times[d++] ++;

	//选择下一个键
	for (int y = 0; y < 16; y++){
		int ni = i + dir[y][0], nj = j + dir[y][1];
		if (canVisit(ni, nj)){	//该点未被选择
			DFS(ni, nj, d);
		}
		else if (y < 8){	//这步最关键,前8个方向的键若被按下了,可以选择同样方向但更远一步的位置
			ni += dir[y][0];
			nj += dir[y][1];
			if (canVisit(ni, nj) ){	//该点未被选择
				DFS(ni, nj, d);
			}
		}
	}
	isVisit[i][j] = false;
	return;
}
solution:
class Solution {
public:
    int solution(int m, int n) {
        if(m > n){    //易被忽略
            return 0;
        }
        m = (m<0? 0: m);    //参数检查必须有
        n = (n>9? 9:n);
        int tmp[] = {0, 9, 56, 320, 1624, 7152, 26016, 72912, 140704, 140704 };
        int ans = 0;
        for(int i=m; i<=n; i++){
           ans += tmp[i];
       }
       return ans;
    }
};



发表于 2020-04-01 21:43:16 回复(6)
# Python3 dfs
# 所有方向
di = [(1,0), (-1,0), (0,1), (0,-1), (1,1), (-1,-1), (1,-1), (-1,1), (1,2), (1,-2), (-1,2), (-1,-2), (2,1), (2,-1),(-2,1),(-2,-1)]
# 可跨一个点的方向
ds = [(1,0), (-1,0), (0,1), (0,-1), (1,1), (-1,-1), (1,-1), (-1,1)]
# 9个点
nodes = {(0,0), (0,1), (0,2), (1,0), (1,1), (1,2), (2,0), (2,1), (2,2)}
def dfs(x, y, visited, count):
    visited.add((x, y))
    count -= 1
    ans = 0
    if count == 0:
        ans += 1
    else:
        for d in di:
            if (x+d[0], y+d[1]) in visited or (x+d[0], y+d[1]) not in nodes:
                if d not in ds:
                    continue
                else:
                    dx = d[0] * 2
                    dy = d[1] * 2
                    if (x+dx, y+dy) in nodes and (x+dx, y+dy) not in visited:
                        ans += dfs(x+dx, y+dy, visited, count)                       
            else:
                ans += dfs(x+d[0], y+d[1], visited, count)
    visited.remove((x, y))
    return ans

ans = [0] * 10
for count in range(1, 10):
    for i in range(3):
        for j in range(3):
            visited = set()
            ans[count] += dfs(i, j, visited, count)
# ans[i]即为i个键的结果数
# ans = [0, 9, 56, 320, 1624, 7152, 26016, 72912, 140704, 140704]
print(ans)
 

编辑于 2020-04-02 18:52:08 回复(2)
class Solution {
public:
    void move(vector<vector<int> >& board, int i, int j, int k, int m, int n, int& ans){
        // 如果已经走过的点数大于等于m,则是有效路径,ans++
        if(k >= m) ans ++;
        // 如果已经走过的点数等于n,则不需要继续探索,故返回
        if(k == n) return;
        // 如果已经走过的点数小于n,则还可以继续探索
        for(int dx=-2; dx<=2; dx++){
            for(int dy=-2; dy<=2; dy++){
                if(i+dx>=0 && i+dx<=2 && j+dy>=0 && j+dy<=2 && board[i+dx][j+dy]==0){
                    // 如果两点之间没有第三个点(条件:dx%2 || dy%2),则无需判断是否经过“已经过”的点
                    // 如果两点之间有第三个点,则需要判断这个点是否是已经走过的点
                    if(dx%2 || dy%2 || (!(dx%2) && !(dy%2) && board[i+dx/2][j+dy/2]==1)){
                        board[i+dx][j+dy] = 1;
                        move(board, i+dx, j+dy, k+1, m, n, ans);
                        board[i+dx][j+dy] = 0;
                    }
                }
            }
        }
         
        return;
    }
     
    int solution(int m, int n) {
        // write code here
        vector<vector<int> > board(3, vector<int>(3, 0));
        int ans = 0;
        // 如果n等于0,则直接返回0
        if(n == 0) return ans;
        
        // 选择棋盘上任意一点作为起点
        for(int i=0; i<3; i++){
            for(int j=0; j<3; j++){
                board[i][j] = 1;
                move(board, i, j, 1, m, n, ans);
                board[i][j] = 0;
            }
        }
        return ans;
    }
};

发表于 2020-04-21 19:06:47 回复(2)

Java版本,比较容易想到,但是调试了很多遍。

public static int solution (int m, int n) {
//         递归实现
         int count = 0;
         n = n>9 ? 9 : n;
         for(int i=m;i<=n;i++) {
             boolean[][] flags = new boolean[3][3];
             for(int j=0;j<3;j++) {
                 for(int t=0;t<3;t++) {
                     count += findNext(flags, j, t, 0, i);
                 }
             }
         }
         return count;
     }

     public static int findNext(boolean[][] flags,int curRow, int curCol, int steps, int n) {
         int count = 0;
         steps ++;
         flags[curRow][curCol] = true;
//         步数走完返回
         if(steps == n)
             return 1;
//         如果可以走,那么返回 1
         for(int i=0;i<3;i++) {
             for(int j=0;j<3;j++) {
                 if(flags[i][j] == false && canStep(flags, curRow, curCol, i, j)) {
                     count += findNext(flags, i, j, steps, n);
//                     恢复状态
                     flags[i][j] = false;
                 }
             }
         }
         flags[curRow][curCol] = false;
         return count;
     }

     public static boolean canStep(boolean[][] flags, int curRow, int curCol, int targetRow, int targetCol) {
//         在同一行
         if(curRow == targetRow) {
             int low = curCol < targetCol?curCol:targetCol;
             if(Math.abs(curCol - targetCol) >1 && flags[curRow][low+1] == false)
                 return false;
         }
//         在同一列
         if(curCol == targetCol) {
             int low = curRow < targetRow?curRow:targetRow;
             if(Math.abs(curRow - targetRow) >1 && flags[low+1][curCol] == false)
                 return false;
         }
//         斜对角
         if(Math.abs(curRow-targetRow)==2 && Math.abs(curCol-targetCol)==2 && flags[1][1] == false)
             return false;
         return true;
     }
发表于 2020-04-24 12:58:52 回复(5)

1、Python3技巧:使用itertools.permutations生成所有可能路径,逐个检查是否可行
2、路径是否可行,取决于相邻两个点的连线之间是否出现还没有经过的点,例如,如果没有先经过点2,那么不能出现连线(1, 3)
3、路径存在镜像对称性,可以节省大量的搜索过程,比如以3、7、9开头的路径可以对称到以1开头的路径,同理以4、6、8开头的路径可以对称到以2开头的路径。

from itertools import permutations

class Solution:
    def solution(self, m, n):
        if n == 0: return 0
        if m == 0: m = 1
        e = {(1, 3), (4, 6), (7, 9),
             (1, 7), (2, 8), (3, 9),
             (1, 9), (3, 7)}
        h, c = {3, 4, 6, 7, 8, 9}, 0
        for k in range(m, n + 1):
            for a in permutations(range(1, 10), k):
                if a[0] in h: continue
                t = set()
                for i in range(len(a) - 1):
                    if (a[i], a[i+1]) in e or (a[i+1], a[i]) in e:
                        if (a[i] + a[i+1]) // 2 not in t: break
                    t.add(a[i])
                else: c += 1 if a[0] == 5 else 4
        return c
发表于 2020-06-05 20:00:17 回复(2)
喵的个㊙的。真不是人做的。这题笔试出来我肯定做不完。千辛万苦不懈奋斗总算把我最初的想法实现了。
struct data
{
    static const int size = 7;
    bool traversed = 0;
    vector<vector<data*>> path;
};
 
class Solution
{
    static const int arrSize = 9;
     
    data d[arrSize];
     
    int total = 0;
     
    void recur(int num, data* target)
    {
        if(num == 1)
            total += 1;
        else if(num < 1 || num > 9)
            ;
        else
        {
            for(int i = 0; i < target->path.size(); i++)
            {
                if(!target->path[i][0]->traversed)
                {
                    target -> traversed = 1;
                    recur(num - 1, target->path[i][0]);
                    target -> traversed = 0;
                }
                else if(target->path[i].size() > 1 && !target->path[i][1]->traversed)
                {
                    target -> traversed = 1;
                    recur(num - 1, target->path[i][1]);
                    target -> traversed = 0;
                }
            }
        }
    }
     
    void reset()
    {
        for(int i = 0; i < arrSize; i++)
        {
            d[i].traversed = 0;
        }
    }
     
public:
    /**
     * 实现方案
     * @param m int整型 最少m个键
     * @param n int整型 最多n个键
     * @return int整型
     */
      
    /*
    0   1   2
     
    3   4   5
     
    6   7   8
    */
    Solution()
    {
        d[0].path.push_back(vector<data*>());
        d[0].path[0].push_back(&d[1]);
        d[0].path[0].push_back(&d[2]);
        d[0].path.push_back(vector<data*>());
        d[0].path[1].push_back(&d[5]);
        d[0].path.push_back(vector<data*>());
        d[0].path[2].push_back(&d[4]);
        d[0].path[2].push_back(&d[8]);
        d[0].path.push_back(vector<data*>());
        d[0].path[3].push_back(&d[7]);
        d[0].path.push_back(vector<data*>());
        d[0].path[4].push_back(&d[3]);
        d[0].path[4].push_back(&d[6]);
         
        d[1].path.push_back(vector<data*>());
        d[1].path[0].push_back(&d[0]);
        d[1].path.push_back(vector<data*>());
        d[1].path[1].push_back(&d[3]);
        d[1].path.push_back(vector<data*>());
        d[1].path[2].push_back(&d[6]);
        d[1].path.push_back(vector<data*>());
        d[1].path[3].push_back(&d[4]);
        d[1].path[3].push_back(&d[7]);     
        d[1].path.push_back(vector<data*>());
        d[1].path[4].push_back(&d[8]);
        d[1].path.push_back(vector<data*>());
        d[1].path[5].push_back(&d[5]);
        d[1].path.push_back(vector<data*>());
        d[1].path[6].push_back(&d[2]);
 
        d[2].path.push_back(vector<data*>());
        d[2].path[0].push_back(&d[1]);
        d[2].path[0].push_back(&d[0]);
        d[2].path.push_back(vector<data*>());
        d[2].path[1].push_back(&d[3]);
        d[2].path.push_back(vector<data*>());
        d[2].path[2].push_back(&d[4]);
        d[2].path[2].push_back(&d[6]);
        d[2].path.push_back(vector<data*>());
        d[2].path[3].push_back(&d[7]);
        d[2].path.push_back(vector<data*>());
        d[2].path[4].push_back(&d[5]);
        d[2].path[4].push_back(&d[8]);
         
        d[3].path.push_back(vector<data*>());
        d[3].path[0].push_back(&d[0]);
        d[3].path.push_back(vector<data*>());
        d[3].path[1].push_back(&d[1]);
        d[3].path.push_back(vector<data*>());
        d[3].path[2].push_back(&d[2]);
        d[3].path.push_back(vector<data*>());
        d[3].path[3].push_back(&d[4]);
        d[3].path[3].push_back(&d[5]);
        d[3].path.push_back(vector<data*>());
        d[3].path[4].push_back(&d[8]);
        d[3].path.push_back(vector<data*>());
        d[3].path[5].push_back(&d[7]);
        d[3].path.push_back(vector<data*>());
        d[3].path[6].push_back(&d[6]);
         
        d[4].path.push_back(vector<data*>());
        d[4].path[0].push_back(&d[0]);
        d[4].path.push_back(vector<data*>());
        d[4].path[1].push_back(&d[1]);
        d[4].path.push_back(vector<data*>());
        d[4].path[2].push_back(&d[2]);
        d[4].path.push_back(vector<data*>());
        d[4].path[3].push_back(&d[3]);
        d[4].path.push_back(vector<data*>());
        d[4].path[4].push_back(&d[5]);
        d[4].path.push_back(vector<data*>());
        d[4].path[5].push_back(&d[6]);
        d[4].path.push_back(vector<data*>());
        d[4].path[6].push_back(&d[7]);
        d[4].path.push_back(vector<data*>());
        d[4].path[7].push_back(&d[8]);
         
        d[5].path.push_back(vector<data*>());
        d[5].path[0].push_back(&d[2]);
        d[5].path.push_back(vector<data*>());
        d[5].path[1].push_back(&d[1]);
        d[5].path.push_back(vector<data*>());
        d[5].path[2].push_back(&d[0]);
        d[5].path.push_back(vector<data*>());
        d[5].path[3].push_back(&d[4]);
        d[5].path[3].push_back(&d[3]);
        d[5].path.push_back(vector<data*>());
        d[5].path[4].push_back(&d[6]);
        d[5].path.push_back(vector<data*>());
        d[5].path[5].push_back(&d[7]);
        d[5].path.push_back(vector<data*>());
        d[5].path[6].push_back(&d[8]);
         
        d[6].path.push_back(vector<data*>());
        d[6].path[0].push_back(&d[3]);
        d[6].path[0].push_back(&d[0]);
        d[6].path.push_back(vector<data*>());
        d[6].path[1].push_back(&d[1]);
        d[6].path.push_back(vector<data*>());
        d[6].path[2].push_back(&d[4]);
        d[6].path[2].push_back(&d[2]);
        d[6].path.push_back(vector<data*>());
        d[6].path[3].push_back(&d[5]);
        d[6].path.push_back(vector<data*>());
        d[6].path[4].push_back(&d[7]);
        d[6].path[4].push_back(&d[8]);
         
        d[7].path.push_back(vector<data*>());
        d[7].path[0].push_back(&d[6]);
        d[7].path.push_back(vector<data*>());
        d[7].path[1].push_back(&d[3]);
        d[7].path.push_back(vector<data*>());
        d[7].path[2].push_back(&d[0]);
        d[7].path.push_back(vector<data*>());
        d[7].path[3].push_back(&d[4]);
        d[7].path[3].push_back(&d[1]);
        d[7].path.push_back(vector<data*>());
        d[7].path[4].push_back(&d[2]);
        d[7].path.push_back(vector<data*>());
        d[7].path[5].push_back(&d[5]);
        d[7].path.push_back(vector<data*>());
        d[7].path[6].push_back(&d[8]);
         
        d[8].path.push_back(vector<data*>());
        d[8].path[0].push_back(&d[7]);
        d[8].path[0].push_back(&d[6]);
        d[8].path.push_back(vector<data*>());
        d[8].path[1].push_back(&d[3]);
        d[8].path.push_back(vector<data*>());
        d[8].path[2].push_back(&d[4]);
        d[8].path[2].push_back(&d[0]);
        d[8].path.push_back(vector<data*>());
        d[8].path[3].push_back(&d[1]);
        d[8].path.push_back(vector<data*>());
        d[8].path[4].push_back(&d[5]);
        d[8].path[4].push_back(&d[2]);
    }
      
    int solution(int m, int n)
    {
        for(int i = m; i <= n; i++)
        {
            for(int j = 0; j < arrSize; j ++)
            {
                recur(i, &d[j]);
            }
        }
        return total;
    }
};



发表于 2020-04-24 01:24:18 回复(3)
要用深度优先解,实在挤不出来了。。。
发表于 2023-09-02 17:53:07 回复(0)
首先想到BFS,然后一顿乱敲
import java.util.*;


public class Solution {
    /**
     * 实现方案
     * @param m int整型 最少m个键
     * @param n int整型 最多n个键
     * @return int整型
     */
    public int solution (int m, int n) {
        // write code here
        if (n == 0 ) {
            return 0;
        }
        int[][] xuanze = new int [3][3];
        Queue<int[]> qe = new LinkedList<>();
        Queue<int[][]> qed = new LinkedList<>();
        int ans = 0;
        for (int i = 0 ; i < 3; i++) {
            for (int j = 0 ; j < 3; j++) {
                qe.offer(new int[] {i, j});
                xuanze[i][j] = 1;
                qed.offer(xuanze);
                int len = 1;
                while (!qe.isEmpty()) {
                    int length = qe.size();
                    if (len >= m) {
                        ans += length;
                    }
                    if (len == n) {
                        qe.clear();
                        qed.clear();
                        break;
                    }
                    while (length > 0) {
                        int[] in = qe.poll();
                        xuanze = qed.poll();
                        for (int i1 = 0; i1 < 3; i1++) {
                            for (int j1 = 0 ; j1 < 3 ; j1++) {
                                if (xuanze[i1][j1] == 1) {
                                    continue;
                                }
                                if ((in[0] + i1 ) % 2 != 0 || (in[1] + j1 ) % 2 != 0) {
                                    qe.offer(new int[] {i1, j1});
                                    int[][] xuanze2 = new int[3][3];
                                    for (int i2 = 0; i2 < 3; i2++) {
                                        xuanze2[i2] = Arrays.copyOf(xuanze[i2], 3);
                                    }
                                    xuanze2[i1][j1] = 1;
                                    qed.add(xuanze2);
                                } else {
                                    if (xuanze[(in[0] + i1 ) / 2][(in[1] + j1 ) / 2] == 0) {
                                        continue;
                                    } else {
                                        qe.offer(new int[] {i1, j1});
                                        int[][] xuanze2 = new int[3][3];
                                        for (int i2 = 0; i2 < 3; i2++) {
                                            xuanze2[i2] = Arrays.copyOf(xuanze[i2], 3);
                                        }
                                        xuanze2[i1][j1] = 1;
                                        qed.add(xuanze2);
                                    }

                                }
                            }
                        }

                        length--;
                    }
                    len++;


                }
                for (int i4 = 0 ; i4 < 3; i4++) {
                    Arrays.fill(xuanze[i4], 0);
                }
            }
            // write code here

        }
        return ans;
    }
}


发表于 2023-03-27 15:16:14 回复(0)

可以知道的是共有24个可能的合法方向
所以将这24个防向预处理出来放在数组中
对于后8个方向,需要判断被跳过的格子有没有被访问过
剩下的dfs解决就好了

int x[] = {0, -1, 0, 1, -1, 1, 1, -1, 2, 2, -2, -2, 1, 1, -1, -1, 2, -2, 2, -2, 2, -2, 0, 0};
int y[] = {1, 0, -1, 0, -1, 1, -1, 1, 1, -1, 1, -1, -2, 2, -2, 2, 2, -2, -2, 2, 0, 0, 2, -2};
class Solution {
public:
    /**
     * 实现方案
     * @param m int整型 最少m个键
     * @param n int整型 最多n个键
     * @return int整型
     */
    bool vis[4][4];
    int _n, _m;
    int ans = 0;
    bool valid(int x, int y){
        return x>=0 && x<3 && y>=0 && y<3 && !vis[x][y];
    }
    void dfs(int row, int col, int cnt){
        if(cnt > _m)
              return;
        if(cnt >= _n && cnt <= _m)
            ans += 1;
        for(int i = 0; i < 24; i++){
            int tempx = row + x[i];
            int tempy = col + y[i];
            if(valid(tempx, tempy)){
                if(i >= 16){
                    int helpx = x[i]/2;
                    int helpy = y[i]/2;
                    if(!vis[row + helpx][col + helpy]){
                        continue;
                    }
                }
                vis[tempx][tempy] = true;
                dfs(tempx, tempy, cnt + 1);
                vis[tempx][tempy] = false;
            }
        }

    }
    int solution(int m, int n) {
        // write code here
        _n = m;
        _m= n;
        ans = 0;
        memset(vis, 0 , sizeof vis);
        for(int i=0; i<3; i++){
            for(int j=0; j<3; j++){
                memset(vis, 0, sizeof vis);
                vis[i][j] = true;
                dfs(i, j, 1);
            }
        }
        return ans;
    }
};
发表于 2021-03-26 14:48:54 回复(0)
class Solution {
public:
    bool matrix[3][3] = {{false, false,false} , 
                         {false, false,false} , 
                         {false, false,false} };
    int m, n;
    int res = 0;
    int solution(int m, int n) {
        // 深度为m到n,深度优先遍历,记录搜索时的深度
        res = 0;
        this->m = m <= 0 ? 1 : m;
        this->n = n > 9 ? 9 : n;
        if (this->m < 1 || this->n < m)
            return 0;
        int length = 0;
        for (int i = 0; i <= 2; ++i)
            for (int j = 0; j <= 2; ++j) {
                dfs(length, i, j);
            }
        return res;
    }
    void dfs(int& length,int i, int j)
    {
        if (length >= n)
            return;
        matrix[i][j] = true;
        length++;
        if (length >= m && length <= n)
            res++;
        for (int x = 0; x <= 2; ++x)
            for (int y = 0; y <= 2; ++y) {
                if (length < n && isVaild(i, j, x, y))
                    dfs(length, x, y);
            }
        length--;
        matrix[i][j] = false;
        return;
    }
    bool isVaild(int i, int j, int x, int y)
    {
        if (x < 0 || y > 2 || x < 0 || y > 2)
            return false;
        if (matrix[x][y] == true)
            return false;
        int midI = (i + x) / 2;
        int midJ = (j + y) / 2;
        if ((abs(x - i) == 0 && abs(y - j) == 2)
            || (abs(x - i) == 2 && abs(y - j) == 0)
            || (abs(x - i) == 2 && abs(y - j) == 2)) {
            if (matrix[midI][midJ] == false)
                return false;
        }
        return true;
    }
};

编辑于 2021-03-06 18:29:18 回复(0)