Langton’s Ant:一只蚂蚁在一个无限大的网格上,网格刚开始全白色,蚂蚁向右,每次移动时:
- 如果在白格上,先反转网格颜色,然后右转,最后前进一格
- 如果在黑格上,先反转网格颜色,然后左转,最后前进一格
模拟蚂蚁K
步的行动,返回蚂蚁能到达的最大矩形网格。
可以开一个足够大的数组,大小为2K + 1
,让蚂蚁从中心开始移动,模拟就好了。虽然这种方法空间开销比较大,但是对于刷题来说,很少会有空间不够用的情况。
为了避免空间浪费,可以动态改变网格的大小,类似vector
扩展的方式,当蚂蚁走到网格外时,倍增网格大小,如果向右或者向下走出了网格,直接在尾部扩展棋盘即可;如果向左或者向上走出了网格,在尾部扩展网格后,需要把蚂蚁的位置以及棋盘整体右移或者下移。
还有几个注意的点:
- 因为蚂蚁的转向需要根据当前格的颜色来确定,所以要用单独的变量记录蚂蚁的位置,最后输出时再修正蚂蚁的位置和方向
- 因为最后输出的网格只包括能到达的网格,为了方便,使用了
4
个额外的变量top
、left
、bottom
和right
记录了网格的范围
class Solution {
private:
vector<string> Grid;
int r = 0, c = 0;
int top = 0, left = 0, bottom = 0, right = 0;
enum class Orientation
{
LEFT, UP, RIGHT, DOWN
};
char flip(){ return Grid[r][c] != 'X' ? 'X' : '_'; }
Orientation moveAnt(Orientation orient)
{
char OldColor = Grid[r][c] != 'X' ? '_' : 'X';
switch(orient)
{
case Orientation::LEFT:
Grid[r][c] = flip();
if(OldColor == '_'){
r--;
top = r < top ? r : top;
return Orientation::UP;
}
else{
r++;
bottom = r > bottom ? r : bottom;
return Orientation::DOWN;
}
case Orientation::UP:
Grid[r][c] = flip();
if(OldColor == '_'){
c++;
right = c > right ? c : right;
return Orientation::RIGHT;
}
else{
c--;
left = c < left ? c : left;
return Orientation::LEFT;
}
case Orientation::RIGHT:
Grid[r][c] = flip();
if(OldColor == '_'){
r++;
bottom = r > bottom ? r : bottom;
return Orientation::DOWN;
}
else{
r--;
top = r < top ? r : top;
return Orientation::UP;
}
case Orientation::DOWN:
Grid[r][c] = flip();
if(OldColor == '_'){
c--;
left = c < left ? c : left;
return Orientation::LEFT;
}
else{
c++;
right = c > right ? c : right;
return Orientation::RIGHT;
}
}
}
void adjustGrid()
{
if(r == static_cast<int>(Grid.size())){
for(int i = 0; i < r; i++)
{
Grid.push_back(string(Grid[0].size(), ' '));
}
}
else if(c == static_cast<int>(Grid[0].size())){
for(auto &str : Grid)
{
str.append(str.size(), ' ');
}
}
else if(r < 0){
int OriginRow = static_cast<int>(Grid.size());
r += OriginRow, top += OriginRow, bottom += OriginRow;
for(int i = 0; i < OriginRow; i++)
{
Grid.push_back(Grid[i]);
Grid[i].assign(Grid[i].size(), ' ');
}
}
else if(c < 0){
int OriginCol = static_cast<int>(Grid[0].size());
c += OriginCol, left += OriginCol, right += OriginCol;
for(auto &str : Grid)
{
str = string(str.size(), ' ') + str;
}
}
}
public:
vector<string> printKMoves(int K) {
Grid.assign(1, string(1, ' '));
Orientation orient = Orientation::RIGHT;
for(int i = 0; i < K; i++)
{
orient = moveAnt(orient);
adjustGrid();
}
if(orient == Orientation::LEFT) Grid[r][c] = 'L';
else if(orient == Orientation::UP) Grid[r][c] = 'U';
else if(orient == Orientation::RIGHT) Grid[r][c] = 'R';
else Grid[r][c] = 'D';
vector<string> ret;
for(int i = top; i <= bottom; i++)
{
ret.push_back("");
for(int j = left; j <= right; j++)
{
if(Grid[i][j] == ' ') ret.back().push_back('_');
else ret.back().push_back(Grid[i][j]);
}
}
return ret;
}
};
动态变化网格比较麻烦,也可以使用映射来记录蚂蚁到达过的点,但是这种方式提升了时间复杂度,力扣上显示测试用例全过了,但是超时了。
class Solution {
private:
map<pair<int, int>, char> Arrival;
int r = 0, c = 0;
int top = 0, left = 0, bottom = 0, right = 0;
enum class Orientation
{
LEFT, UP, RIGHT, DOWN
};
Orientation moveAnt(Orientation orient)
{
auto iter = Arrival.find(make_pair(r, c));
char OldColor = iter != Arrival.end() ? iter->second : '_';
switch(orient)
{
case Orientation::LEFT:
if(OldColor == '_'){
Arrival[make_pair(r, c)] = 'X';
r--;
top = r < top ? r : top;
return Orientation::UP;
}
else{
Arrival[make_pair(r, c)] = '_';
r++;
bottom = r > bottom ? r : bottom;
return Orientation::DOWN;
}
case Orientation::UP:
if(OldColor == '_'){
Arrival[make_pair(r, c)] = 'X';
c++;
right = c > right ? c : right;
return Orientation::RIGHT;
}
else{
Arrival[make_pair(r, c)] = '_';
c--;
left = c < left ? c : left;
return Orientation::LEFT;
}
case Orientation::RIGHT:
if(OldColor == '_'){
Arrival[make_pair(r, c)] = 'X';
r++;
bottom = r > bottom ? r : bottom;
return Orientation::DOWN;
}
else{
Arrival[make_pair(r, c)] = '_';
r--;
top = r < top ? r : top;
return Orientation::UP;
}
case Orientation::DOWN:
if(OldColor == '_'){
Arrival[make_pair(r, c)] = 'X';
c--;
left = c < left ? c : left;
return Orientation::LEFT;
}
else{
Arrival[make_pair(r, c)] = '_';
c++;
right = c > right ? c : right;
return Orientation::RIGHT;
}
default:;
}
return orient;
}
public:
vector<string> printKMoves(int K) {
Arrival.insert(make_pair(make_pair(0, 0), '_'));
Orientation orient = Orientation::RIGHT;
for(int i = 0; i < K; i++)
{
orient = moveAnt(orient);
}
if(orient == Orientation::LEFT) Arrival[make_pair(r, c)] = 'L';
else if(orient == Orientation::UP) Arrival[make_pair(r, c)] = 'U';
else if(orient == Orientation::RIGHT) Arrival[make_pair(r, c)] = 'R';
else Arrival[make_pair(r, c)] = 'D';
vector<string> ret;
for(int i = top; i <= bottom; i++)
{
ret.push_back("");
for(int j = left; j <= right; j++)
{
auto iter = Arrival.find(make_pair(i, j));
if(iter == Arrival.end()) ret.back().push_back('_');
else ret.back().push_back(iter->second);
}
}
return ret;
}
};