leetcode130_被围绕的区域

一.  这一题也是回溯算法,因为对题目理解不太清楚,所以就直接看大神解法了.

二.  参考

作者:Ac_pipe
链接:https://leetcode-cn.com/problems/surrounded-regions/solution/bfsdi-gui-dfsfei-di-gui-dfsbing-cha-ji-by-ac_pipe/

思路:1. 这道题我们拿到基本就可以确定是图的 dfs、bfs 遍历的题目了。题目中解释说被包围的区间不会存在于边界上,所以我们会想到边界上的 O 要特殊处理,只要把边界上的 O 特殊处理了,那么剩下的 O 替换成 X 就可以了。问题转化为,如何寻找和边界联通的 O.

2. 这时候的 O 是不做替换的。因为和边界是连通的。为了记录这种状态,我们把这种情况下的 O 换成 # 作为占位符,待搜索结束之后,遇到 O 替换为 X(和边界不连通的 O);遇到 #,替换回 O(和边界连通的 O)。

3. 如何寻找和边界联通的O? 从边界出发,对图进行 dfs 和 bfs 即可。这里简单总结下 dfs 和 bfs

bfs 递归。可以想想二叉树中如何递归的进行层序遍历。
bfs 非递归。一般用队列存储。
dfs 递归。最常用,如二叉树的先序遍历。
dfs 非递归。一般用 stack。

三.  dfs递归

//这个没有使用visited数组标记有无使用过这个数.而是改用不同的符号#去标记.
class Solution {
public:
	void dfs(vector<vector<char>>& board, int i, int j) {
		//终止条件,要不超出范围,要不碰到#或者X.
		if (i >= board.size() || i < 0 || j < 0 ||
			j >= board[0].size() || board[i][j] == '#' || board[i][j] == 'X')
			return;
		//边界的标记为特殊的符号.
		board[i][j] = '#';
		dfs(board, i + 1, j);//下
		dfs(board, i - 1, j);//上
		dfs(board, i, j + 1);//右
		dfs(board, i, j - 1);//左
	}
	void solve(vector<vector<char>>& board) {
		//边界条件.
		if (board.size() == 0 || board[0].size() == 0)
			return;
		int m = board.size(), n = board[0].size();
		bool b;
		for (int i = 0; i < m; i++) {
			for (int j = 0; j < n; j++) {
				//遍历数组,先解决边界的O问题.
				//如果i,j处于边界上,且为O.
				//则dfs,深度优先搜索.
				b = (i == 0 || i == m - 1 || j == 0 || j == n - 1);
				if (b && board[i][j] == 'O')
					dfs(board, i, j);
			}
		}
		for (int i = 0; i < m; i++) {
			for (int j = 0; j < n; j++) {
				if (board[i][j] == '#')
					board[i][j] = 'O';
				else if (board[i][j] == 'O')
					board[i][j] = 'X';
			}
		}
	}
};

四. 继续参考下一个大神的,可以用作回溯的通用模板了.

作者:windliang
链接:https://leetcode-cn.com/problems/surrounded-regions/solution/xiang-xi-tong-su-de-si-lu-fen-xi-duo-jie-fa-by-3-6/

1.  解法一是从当前节点做 DFS ,然后看它是否能到达边界的 O。那么我们能不能把思路逆转过来呢?

2.  从边界的 O 做 DFS,然后把遇到的 O 都标记一下,这些 O 就是可以连通到边界的。然后把边界的所有的 O 都做一次 DFS ,把 DFS 过程的中的 O 做一下标记。最后我们只需要遍历节点,把没有标记过的 O 改成 X 就可以了。

3.  标记的话,我们可以用一个 visited 二维数组,把访问过的置为 true .(这是一个技巧)

class Solution {
public:
	//记住,传入数组时一定要传入他的地址,不然值不会改变.
	void dfs(int i, int j, vector<vector<char>>& board, vector<vector<int>>& visited) {
		if (i < 0 || i >= board.size() || j < 0 || j >= board[0].size())
			return;
		if (visited[i][j] == 1)
			return;
		//如果遇到'X',都不满足条件,则直接返回.
		if (board[i][j] == 'O') {
			//将当前坐标设置为1,注意是当前的.
			visited[i][j] = 1;
			dfs(i + 1, j, board, visited);
			dfs(i - 1, j, board, visited);
			dfs(i, j + 1, board, visited);
			dfs(i, j - 1, board, visited);
		}

	}
	void solve(vector<vector<char>>& board) {
		//边界条件.
		if (board.size() == 0 || board[0].size() == 0)
			return;
		int m = board.size(), n = board[0].size();
		vector<vector<int>> visited(m, vector<int>(n, 0));
		//直接把边界找出来对边界处理.
		for (int j = 0; j < n; j++) {
			if (board[0][j] == 'O')
				dfs(0, j, board, visited);
			if (board[m - 1][j] == 'O') {
				dfs(m - 1, j, board, visited);
			}
		}
		for (int i = 0; i < m; i++) {
			if (board[i][0] == 'O')
				dfs(i, 0, board, visited);
			if (board[i][n - 1] == 'O')
				dfs(i, n - 1, board, visited);
		}
		for (int i = 0; i < m; i++) {
			for (int j = 0; j < n; j++) {
				if (visited[i][j] == 1)
					board[i][j] = 'O';
				else if (board[i][j] == 'O')
					board[i][j] = 'X';
			}
		}
	}
};

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
题目描述: 给定一个字符串,请将字符串里的字符按照出现的频率降序排列。 示例 1: 输入: "tree" 输出: "eert" 解释: 'e'出现两次,'r'和't'都只出现一次。因此'e'必须出现在'r'和't'之前。此外,"eetr"也是一个有效的答案。 示例 2: 输入: "cccaaa" 输出: "cccaaa" 解释: 'c'和'a'都出现三次。此外,"aaaccc"也是有效的答案。注意"cacaca"是不正确的,因为相同的字母必须放在一起。 示例 3: 输入: "Aabb" 输出: "bbAa" 解释: 此外,"bbaA"也是一个有效的答案,但"Aabb"是不正确的。注意'A'和'a'被认为是两种不同的字符。 Java代码如下: ``` import java.util.*; public class Solution { public String frequencySort(String s) { if (s == null || s.length() == 0) { return ""; } Map<Character, Integer> map = new HashMap<>(); for (int i = 0; i < s.length(); i++) { char c = s.charAt(i); map.put(c, map.getOrDefault(c, 0) + 1); } List<Map.Entry<Character, Integer>> list = new ArrayList<>(map.entrySet()); Collections.sort(list, (o1, o2) -> o2.getValue() - o1.getValue()); StringBuilder sb = new StringBuilder(); for (Map.Entry<Character, Integer> entry : list) { char c = entry.getKey(); int count = entry.getValue(); for (int i = 0; i < count; i++) { sb.append(c); } } return sb.toString(); } } ``` 解题思路: 首先遍历字符串,使用HashMap记录每个字符出现的次数。然后将HashMap转换为List,并按照出现次数从大到小进行排序。最后遍历排序后的List,将每个字符按照出现次数依次添加到StringBuilder中,并返回StringBuilder的字符串形式。 时间复杂度:O(nlogn),其中n为字符串s的长度。遍历字符串的时间复杂度为O(n),HashMap和List的操作时间复杂度均为O(n),排序时间复杂度为O(nlogn),StringBuilder操作时间复杂度为O(n)。因此总时间复杂度为O(nlogn)。 空间复杂度:O(n),其中n为字符串s的长度。HashMap和List的空间复杂度均为O(n),StringBuilder的空间复杂度也为O(n)。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值