LeetCode刷题——机器人的运动范围

题目要求:
地上有一个m行n列的方格,从坐标 [0,0] 到坐标 [m-1,n-1] 。一个机器人从坐标 [0, 0] 的格子开始移动,它每次可以向左、右、上、下移动一格(不能移动到方格外),也不能进入行坐标和列坐标的数位之和大于k的格子。例如,当k为18时,机器人能够进入方格 [35, 37] ,因为3+5+3+7=18。但它不能进入方格 [35, 38],因为3+5+3+8=19。请问该机器人能够到达多少个格子?

示例 1:
输入:m = 2, n = 3, k = 1
输出:3

示例 2:
输入:m = 3, n = 1, k = 0
输出:1

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/ji-qi-ren-de-yun-dong-fan-wei-lcof
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

我的思路:
先把所有符合条件的点,也就是数位之和i+数位之和j <= k的点标为0。不符合条件的数位标为2。然后从[0][0]开始搜索,能到的、而且是0的地方标为1。
转换成常规的广度优先搜索问题,借鉴之前的岛屿面积和走迷宫问题。
这里值得注意的是,由于从[0][0]开始走,故只需要考虑向下和向右的两个方向。

int shuwei(int x) {//求数位
	int ans = 0;
	while ( x )
	{
		ans += x % 10;
		x /= 10;
	}
	return ans;
}


int movingCount(int m, int n, int k) {
	vector<vector<int>> map;
	for (size_t i = 0; i < m; i++) { //为每个格子检查下是否符合要求
		vector <int> eve;
		for (size_t j = 0; j < n; j++)
		{
			if (shuwei(i) + shuwei(j) <= k)
				eve.push_back(0);
			else
				eve.push_back(2);
		}
		map.push_back(eve);
	}

	//init

	stack<int> stacki;
	stack<int> stackj;              // 两个栈分别储存 i、j 坐标
	stacki.push(0);	stackj.push(0);
	int add[2][2]{ {0,1},{1,0}};
	while (!stacki.empty()) {
		int cur_i = stacki.top(), cur_j = stackj.top();
		stacki.pop(); stackj.pop();
		if (cur_i >= m || cur_j >= n || map[cur_i][cur_j] != 0) 
		//只向右或向下走,则i、j必大于0,如果合法就把它的下边第一个和右边第一个压入栈中
		continue;
		map[cur_i][cur_j] = 1; ///标记这个区域可以进入
		for (size_t z = 0; z < 2; z++)
		{
			int next_i = cur_i + add[z][0];
			int next_j = cur_j + add[z][1];
			stacki.push(next_i);
			stackj.push(next_j);
		}
	}

	int count = 0; 
	for (size_t i = 0; i < m; i++)                 //最后遍历一遍有几个符合条件
		for (size_t j = 0; j < n; j++)
		{
			if (map[i][j] == 1)
				count++;
		}
	return count;
}

官方解答 :
方法一:类似思想

class Solution {
    // 计算 x 的数位之和
    int get(int x) {
        int res=0;
        for (; x; x /= 10) {
            res += x % 10;
        }
        return res;
    }
public:
    int movingCount(int m, int n, int k) {
        if (!k) return 1;
        queue<pair<int,int> > Q; // 由两个数作为基本元素组成的队列
        // 向右和向下的方向数组
        int dx[2] = {0, 1};
        int dy[2] = {1, 0};
        vector<vector<int> > vis(m, vector<int>(n, 0)); //构造m*n0矩阵
        Q.push(make_pair(0, 0)); //放入把起始点00作为首元素放入队列
        vis[0][0] = 1;
        int ans = 1;
        while (!Q.empty()) {
            auto x = Q.front().first; // 这么取出 pair 中的数
            auto y = Q.front().second;
            Q.pop();
            for (int i = 0; i < 2; ++i) {
                int tx = dx[i] + x;
                int ty = dy[i] + y;
                if (tx < 0 || tx >= m || ty < 0 || ty >= n || vis[tx][ty] || get(tx) + get(ty) > k) continue;
                Q.push(make_pair(tx, ty));
                vis[tx][ty] = 1;
                ans++;
            }
        }
        return ans;
    }
};

作者:LeetCode-Solution
链接:https://leetcode-cn.com/problems/ji-qi-ren-de-yun-dong-fan-wei-lcof/solution/ji-qi-ren-de-yun-dong-fan-wei-by-leetcode-solution/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

其中需要学习的有 二维vector向量的表示方法:

1.vector<vector > vis(m, vector(n, 0)) vis 即为m行,每行是n个0 的vector < int > 的二维vector int 数组。
2.pair与make_pair的用法,以及对于pair对象通过.first \ .second 取出第一、第二个元素

方法二:
递推,由于从0 0 出发,则一个块能到,则必须满足它的上方可以到或者它的下方可以到,遍历即可。

 int get(int x) {
        int res=0;
        for (; x; x /= 10){
            res += x % 10;
        }
        return res;
    }
public:
    int movingCount(int m, int n, int k) {
        if (!k) return 1;
        vector<vector<int> > vis(m, vector<int>(n, 0)); //已经把所有数归0了
        int ans = 1;
        vis[0][0] = 1;
        for (int i = 0; i < m; ++i) {
            for (int j = 0; j < n; ++j) {
                if ((i == 0 && j == 0) || get(i) + get(j) > k) continue;
                // 边界判断
                if (i - 1 >= 0) vis[i][j] |= vis[i - 1][j]; 
                if (j - 1 >= 0) vis[i][j] |= vis[i][j - 1]; //如果前边或上边有一个能走到,而这个又符合条件,那么即可走到
                ans += vis[i][j];
            }
        }
        return ans;
    }

作者:LeetCode-Solution
链接:https://leetcode-cn.com/problems/ji-qi-ren-de-yun-dong-fan-wei-lcof/solution/ji-qi-ren-de-yun-dong-fan-wei-by-leetcode-solution/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

需要学习的有
**1.与、异或、或运算符,即&、^、| **

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值