935. Knight Dialer

在这里插入图片描述
又是一道很有意思的题目。
自己又没有想到图上面去:(
以后类似这种两点之间有关联的,可以联想到图上面去,把邻接表写出来就容易多了。

class Solution {
public:
    int knightDialer(int N) {
        vector<vector<int>> adj{{4, 6}, {6, 8}, {7, 9}, {4, 8}, {0, 3, 9}, {}, {0, 1, 7}, {2, 6}, {1, 3}, {2, 4}};
        
        map<pair<int, int>, int> memo;
        int cnt = 0;
        for (int i = 0; i <= 9; ++i)
            cnt = (cnt + helper(adj, memo, i, N-1)) % MOD;
        return cnt;
    }
private:
    int MOD = 1e9 + 7;
    int helper(vector<vector<int>>& adj, map<pair<int, int>, int>& memo, int pos, int steps) {
        if (steps == 0)
            return 1;
        if (pos == 5)//为了提高效率,没有这一句也是对的
            return 0;
        auto key = make_pair(pos, steps);
        if (memo.find(key) != memo.end())
            return memo[key];
        int cnt = 0;
        for (int nextPos : adj[pos])
            cnt = (cnt + helper(adj, memo, nextPos, steps-1)) % MOD;
        memo[key] = cnt;
        if (pos == 5)
            cout << pos << " " << steps << " " << cnt << endl;
        return cnt;
    }
};
//想像成一个图的题目,可以走的两个键可以看成是相邻的两个点。把邻接表写出来,然后按着邻接表来走。这是没有想出来的关键。

//然后可以意识到重叠子问题:状态是<当前位置,还剩步数>

//对于5这个特殊键:如果最后一步走到5上,返回1;如果不是最后一步走到5上,那么就应该返回0,因为走不出去了,不能把所有步数都走完

后来发现超时。可能每次都make_pair时间有点久,而且map的查询时间也不是常数。
下面换成二维数组来存储。

class Solution {
public:
    int knightDialer(int N) {
        vector<vector<int>> adj{{4, 6}, {6, 8}, {7, 9}, {4, 8}, {0, 3, 9}, {}, {0, 1, 7}, {2, 6}, {1, 3}, {2, 4}};
        
        vector<vector<int>> memo(10, vector<int>(N, -1));
        int cnt = 0;
        for (int i = 0; i <= 9; ++i)
            cnt = (cnt + helper(adj, memo, i, N-1)) % MOD;
        return cnt;
    }
private:
    int MOD = 1e9 + 7;
    int helper(vector<vector<int>>& adj, vector<vector<int>>& memo, int pos, int steps) {
        if (steps == 0)
            return 1;
        if (pos == 5)
            return 0;
        if (memo[pos][steps] != -1)
            return memo[pos][steps];
        int cnt = 0;
        for (int nextPos : adj[pos])
            cnt = (cnt + helper(adj, memo, nextPos, steps-1)) % MOD;
        memo[pos][steps] = cnt;
        return cnt;
    }
};
//想像成一个图的题目,可以走的两个键可以看成是相邻的两个点。把邻接表写出来,然后按着邻接表来走。这是没有想出来的关键。

//然后可以意识到重叠子问题:状态是<当前位置,还剩步数>

//对于5这个特殊键:如果最后一步走到5上,返回1;如果不是最后一步走到5上,那么就应该返回0,因为走不出去了,不能把所有步数都走完

总的来说,想到用图,然后写出邻接表,就好多了。memo只是之后的优化

posted @ 2019-09-26 16:02  于老师的父亲王老爷子  阅读(18)  评论(0)    收藏  举报