程序员面试金典 16.22

Langton’s Ant:一只蚂蚁在一个无限大的网格上,网格刚开始全白色,蚂蚁向右,每次移动时:

  • 如果在白格上,先反转网格颜色,然后右转,最后前进一格
  • 如果在黑格上,先反转网格颜色,然后左转,最后前进一格
    模拟蚂蚁K步的行动,返回蚂蚁能到达的最大矩形网格。

可以开一个足够大的数组,大小为2K + 1,让蚂蚁从中心开始移动,模拟就好了。虽然这种方法空间开销比较大,但是对于刷题来说,很少会有空间不够用的情况。

为了避免空间浪费,可以动态改变网格的大小,类似vector扩展的方式,当蚂蚁走到网格外时,倍增网格大小,如果向右或者向下走出了网格,直接在尾部扩展棋盘即可;如果向左或者向上走出了网格,在尾部扩展网格后,需要把蚂蚁的位置以及棋盘整体右移或者下移。

还有几个注意的点:

  • 因为蚂蚁的转向需要根据当前格的颜色来确定,所以要用单独的变量记录蚂蚁的位置,最后输出时再修正蚂蚁的位置和方向
  • 因为最后输出的网格只包括能到达的网格,为了方便,使用了4个额外的变量topleftbottomright记录了网格的范围
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;
    }
};
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值