LeetCode 351. 安卓系统手势解锁 (枚举子集+全排列、回溯)

351. 安卓系统手势解锁

方法一

实际上就是 A ( 9 , i ) A(9,i) A(9,i)的实现,先通过状态的枚举求出子集,然后使用next_permutation()求出全排列。

const int N = 400000;
class Solution {
public:

    pair<int,int> toDot(int x) {
        return {x/3,x - x/3*3};
    }

    bool ok(vector<int>& a) {
        bool vis[10] = {0};
        vis[a[0]] = 1;
        for(int i = 1; i < a.size(); i++) {
            auto p1 = toDot(a[i-1]);
            auto p2 = toDot(a[i]);
            if( abs(p1.first - p2.first) == 2 || abs(p1.second - p2.second) == 2 ) {
                double x = (a[i-1] + a[i])/2.0;
                if(x == (int)x ) {
                    if(vis[(int)x] == false) {
                        return false;
                    }
                }
            }
            vis[a[i]] = 1;
        }
        return true;
    }

    int cal(vector<int>& a) {
        int res = 0;
        do {
            res += ok(a);
        }while(next_permutation(a.begin(),a.end()));
        return res;
    }

    int numberOfPatterns(int m, int n) {
        if(m > n) return 0;
        int limit = 1<<9;
        int f[10] = {0};
        vector<int> a;
        for(int s = 0; s < limit; s++) {
            a.clear();
            for(int i = 0; i < 9; i++) {
                if((s>>i)&1) {
                    a.push_back(i);
                }
            }
            if(a.size() >= m && a.size() <= n) {
                f[a.size()] += cal(a);
            }
        }
        int ans = 0;
        for(int i = m; i <= n; i++) {
            ans += f[i];
        }
        return ans;
    }
};

方法二

普通的回溯法,主要是判断下棋的合法性需要注意一点。

class Solution {
    struct Dot {
        int x;
        int y;
    };
public:
    vector<Dot> dots;
    bool vis[3][3];

    void dfs(Dot d1,int step) {
        if(step > n) return;
        if(step >= m && step <= n) {
            ans++;
        }
        for(auto d2:dots) {
            if(vis[d2.x][d2.y]) continue;
            if(abs(d1.x - d2.x) == 2 || abs(d1.y - d2.y) == 2) {
                double midX = (d1.x + d2.x)/2.0;
                double midY = (d1.y + d2.y)/2.0;
                if(midX == (int)midX && midY == (int)midY) {
                    if(!vis[(int)midX][(int)midY]) continue;
                }
            }
            vis[d2.x][d2.y] = 1;
            dfs(d2,step + 1);
            vis[d2.x][d2.y] = 0;
        }
    }


    int ans = 0;
    int m, n;
    int numberOfPatterns(int m, int n) {
        this->m = m;
        this->n = n;
        for(int i = 0; i < 3; i++) {
            for(int j = 0; j < 3; j++) {
                dots.push_back({i,j});
            }
        }
        for(Dot dot:dots) {
            memset(vis,0,sizeof(vis));
            vis[dot.x][dot.y] = 1;
            dfs(dot,1);
        }
        return ans;
    }
};
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值