last
题目描述
给定一个钥匙和一个锁的初始状态,钥匙是一把不同于普通钥匙的“方形”钥匙,锁的状态为关闭状态。
我们需要将这个“方形”钥匙插入到锁中打开锁。
钥匙和锁的状态分别用字符串表示,其中钥匙字符串中的字母表示钥匙上的钥匙牙,锁字符串中同样表示锁上的锁孔。
钥匙和锁字符串中只包含字母,并且长度不超过100。
钥匙可以旋转,而锁和钥匙可以任意摆放。
例如:钥匙"abc"可以旋转为"cab"、"bca"、"abc"等形式。
当钥匙的某个钥匙牙与某个锁孔对应时,我们可以将这个钥匙牙插入锁孔打开锁。这个过程中钥匙牙需要顺时针或逆时针旋转90度。
问是否可以将“方形”钥匙插入到锁中打开锁。如果可以返回true,否则返回false。
设计思路
由于钥匙可以旋转,因此对于每个钥匙的每个钥匙牙都可以旋转得到不同的形式。因此我们可以考虑使用一个函数来更新钥匙的形态。
对于每个旋转后的钥匙形态,我们可以对于锁的每个锁孔进行尝试,如果能够匹配,就返回true。遍历完所有的钥匙形态以及所有的锁孔后如果还没能找到一个匹配则返回false。
程序流程图
1. 定义一个函数来进行旋转钥匙的操作,将旋转后的钥匙形态保存在vector中。
2. 遍历vector,对于每个钥匙形态,遍历锁孔进行匹配。
3. 如果匹配成功,则返回true,否则继续匹配。
4. 如果在遍历所有钥匙形态和所有锁孔后都不能匹配成功,则返回false。
代码实现
class Solution {
public:
bool check(vector<vector<char>>& lock, vector<vector<char>>& key, int offsetx, int offsety) {
int m = lock.size(), n = lock[0].size();
int cnt = 0;
for (int i = 0; i < n; i++) {
for (int j = 0; j < n; j++) {
int x = i - offsetx, y = j - offsety;
if (x >= 0 && x < m && y >= 0 && y < m) {
if (lock[i][j] == '.') continue;
if (lock[i][j] == key[x][y]) {
cnt++;
} else {
return false;
}
} else {
if (key[x][y] == '.') continue;
return false;
}
}
}
return cnt == cntkey;
}
vector<vector<char>> rotate(vector<vector<char>>& key) {
int m = key.size();
vector<vector<char>> res(m, vector<char>(m));
for (int i = 0; i < m; i++) {
for (int j = 0; j < m; j++) {
res[j][m-1-i] = key[i][j];
}
}
return res;
}
bool canOpenLock(vector<vector<char>>& lock, vector<vector<char>>& key) {
int m = lock.size(), n = lock[0].size();
cntkey = 0;
for (auto& row: key) {
for (auto& c: row) {
if (c != '.') cntkey++;
}
}
vector<vector<char>> cur = key;
for (int i = 0; i < 4; i++) {
cur = rotate(cur);
for (int j = -m; j < m; j++) {
for (int k = -m; k < m; k++) {
if (check(lock, cur, j, k)) {
return true;
}
}
}
}
return false;
}
private:
int cntkey;
};

浙公网安备 33010602011771号