695.岛屿的最大面经
题解1:使用dfs进行搜索,设置一个visited数组记录访问情况,每次进入dfs将岛屿面积加一,直到越界或遇到海水或已经访问过该点。
class Solution {
public:
void dfs(vector<vector<int>>& grid,int i, int j, vector<vector<bool>>& visited, int &res) //用引用来记录面积
{
if(i < 0 || i == grid.size() || j < 0 || j == grid[0].size() || grid[i][j] == 0 || visited[i][j])
return;
visited[i][j] = true;
res++;
dfs(grid, i + 1, j, visited, res);
dfs(grid, i - 1, j, visited, res);
dfs(grid, i, j - 1, visited, res);
dfs(grid, i, j + 1, visited, res);
}
int maxAreaOfIsland(vector<vector<int>>& grid) {
int max_land = 0;
vector<vector<bool>> visited(grid.size(), vector<bool>(grid[0].size(), false));
for(int i = 0;i<grid.size();i++)
{
for(int j = 0;j<grid[0].size();j++)
{
if(grid[i][j] == 1 && !visited[i][j])
{
int temp_land = 0;
dfs(grid, i, j, visited, temp_land);
if(max_land < temp_land)
max_land = temp_land;
}
}
}
return max_land;
}
};
题解2:使用bfs搜索,遍历地图,当点为1时将点的地址放入队列中,并将其设置为0,向4个方向搜索并记录岛屿面积。遍历完成后进行比较即可。
class Solution {
public:
int maxAreaOfIsland(vector<vector<int>>& grid) {
queue<pair<int, int>> index;
vector<int> h = {-1, 0 ,1 ,0 ,-1};
int max_land = 0;
for(int i = 0;i<grid.size();i++)
{
for(int j = 0;j<grid[0].size();j++)
{
int temp_land = 0;
if(grid[i][j] == 1)
{
index.push(make_pair(i, j));
grid[i][j] = 0;
temp_land++;
while(!index.empty())
{
int index_size = index.size();
while(index_size--)
{
auto temp_index = index.front();
index.pop();
for(int k = 0; k < 4;k++)
{
int r = temp_index.first + h[k], c = temp_index.second + h[k + 1];
if(r >= 0 && r < grid.size() && c >= 0 && c < grid[0].size() && grid[r][c] == 1)
{
grid[r][c] = 0;
temp_land++;
index.push(make_pair(r, c));
}
}
}
}
}
if(max_land < temp_land)
{
max_land = temp_land;
}
}
}
return max_land;
}
};
417.太平洋大西洋水流问题
题解1:该题采用水倒流的思路,即从每条边为起始,搜索水能够倒流到的每一个点并记录其状态,最后判断能否到达两个海洋。
class Solution {
public:
vector<int> h = {-1, 0, 1, 0, -1};
void dfs(vector<vector<int>>& heights, int i, int j, vector<vector<bool>>& can_reach)
{
if(can_reach[i][j]) return;
can_reach[i][j] = true;
for(int k = 0;k<4;k++)
{
int r = i + h[k], c = j + h[k+1];
if(r >= 0 && r < heights.size() && c >= 0 && c < heights[0].size() && heights[r][c] >= heights[i][j])
{
dfs(heights, r, c, can_reach);
}
}
}
vector<vector<int>> pacificAtlantic(vector<vector<int>>& heights) {
int n = heights.size(), m = heights[0].size();
vector<vector<bool>> can_reach_pacific(n, vector<bool>(m, false));
vector<vector<bool>> can_reach_atlantic(n, vector<bool>(m, false));
for(int i = 0;i<n;i++)
{
dfs(heights, i, 0, can_reach_pacific);
dfs(heights, i, m - 1, can_reach_atlantic);
}
for(int j = 0;j<m;j++)
{
dfs(heights, 0, j, can_reach_pacific);
dfs(heights, n - 1, j, can_reach_atlantic);
}
vector<vector<int>> res;
for(int i = 0;i<n;i++)
{
for(int j =0;j<m;j++)
{
if(can_reach_atlantic[i][j] && can_reach_pacific[i][j])
{
res.push_back(vector<int>{i, j});
}
}
}
return res;
}
};
题解2:采用bfs,思路同上
class Solution {
public:
vector<vector<int>> pacificAtlantic(vector<vector<int>>& heights) {
int n = heights.size(), m = heights[0].size();
vector<int> h = {-1, 0, 1, 0, -1};
vector<vector<bool>> can_reach_pacific(n, vector<bool>(m, false));
vector<vector<bool>> can_reach_atlantic(n, vector<bool>(m, false));
queue<pair<int, int>> path;
for(int i = 0;i<n;i++)
{
path.push(make_pair(i, 0));
can_reach_pacific[i][0] = true;
while(!path.empty())
{
int path_size = path.size();
while(path_size--)
{
auto temp_path = path.front();
path.pop();
for(int k = 0;k < 4;k++)
{
int r = temp_path.first + h[k], c = temp_path.second + h[k + 1];
if(r >= 0 && r < n && c >=0 && c < m &&
heights[r][c] >= heights[temp_path.first][temp_path.second] && !can_reach_pacific[r][c])
{
path.push(make_pair(r, c));
can_reach_pacific[r][c] = true;
}
}
}
}
path.push(make_pair(i, m - 1));
can_reach_atlantic[i][m - 1] = true;
while(!path.empty())
{
int path_size = path.size();
while(path_size--)
{
auto temp_path = path.front();
path.pop();
for(int k = 0;k < 4;k++)
{
int r = temp_path.first + h[k], c = temp_path.second + h[k + 1];
if(r >= 0 && r < n && c >=0 && c < m
&& heights[r][c] >= heights[temp_path.first][temp_path.second] && !can_reach_atlantic[r][c])
{
path.push(make_pair(r, c));
can_reach_atlantic[r][c] = true;
}
}
}
}
}
for(int j = 0;j < m;j++)
{
path.push(make_pair(0, j));
can_reach_pacific[0][j] = true;
while(!path.empty())
{
int path_size = path.size();
while(path_size--)
{
auto temp_path = path.front();
path.pop();
for(int k = 0;k < 4;k++)
{
int r = temp_path.first + h[k], c = temp_path.second + h[k + 1];
if(r >= 0 && r < n && c >=0 && c < m &&
heights[r][c] >= heights[temp_path.first][temp_path.second] && !can_reach_pacific[r][c])
{
path.push(make_pair(r, c));
can_reach_pacific[r][c] = true;
}
}
}
}
path.push(make_pair(n - 1, j));
can_reach_atlantic[n - 1][j] = true;
while(!path.empty())
{
int path_size = path.size();
while(path_size--)
{
auto temp_path = path.front();
path.pop();
for(int k = 0;k < 4;k++)
{
int r = temp_path.first + h[k], c = temp_path.second + h[k + 1];
if(r >= 0 && r < n && c >=0 && c < m
&& heights[r][c] >= heights[temp_path.first][temp_path.second] && !can_reach_atlantic[r][c])
{
path.push(make_pair(r, c));
can_reach_atlantic[r][c] = true;
}
}
}
}
}
vector<vector<int>> res;
for(int i = 0;i<n;i++)
{
for(int j = 0;j<m;j++)
{
if(can_reach_atlantic[i][j] && can_reach_pacific[i][j])
{
res.push_back(vector<int>{i, j});
}
}
}
return res;
}
};
547.省份数量
题解1:给了图的邻接矩阵,通过dfs遍历可以将相连的节点记录,因此只需遍历节点,记录节点状态,在遍历完一个连同区域后结束遍历,num 加一。
class Solution {
public:
void dfs(vector<vector<int>>& isConnected, int i, vector<bool>& visited)
{
visited[i] = true;
for(int j = 0;j < isConnected[i].size();j++)
{
if(isConnected[i][j] == 1 && !visited[j])
{
dfs(isConnected, j, visited);
}
}
}
int findCircleNum(vector<vector<int>>& isConnected) {
int num = 0;
vector<bool> visited(isConnected.size(), false);
for(int i = 0;i<isConnected.size();i++)
{
if(!visited[i])
{
dfs(isConnected, i, visited);
num++;
}
}
return num;
}
};
题解2:采用bfs,将节点作为加入队列的元素,记录节点状态,思路同dfs的遍历。
class Solution {
public:
int findCircleNum(vector<vector<int>>& isConnected) {
int sum = 0;
queue<int> path;
vector<bool> visited(isConnected.size(), false);
for(int i = 0;i<isConnected.size();i++)
{
if(!visited[i])
{
path.push(i);
while(!path.empty())
{
auto temp_path = path.front();
path.pop();
for(int j = 0;j < isConnected[temp_path].size();j++)
{
if(isConnected[temp_path][j] == 1 && !visited[j])
{
path.push(j);
visited[j] = true;
}
}
}
sum++;
}
}
return sum;
}
};
46.全排列
题解:画出树,采用dfs+回溯,横向遍历纵向递归。
class Solution {
public:
void dfs(vector<int>& nums, int depth, vector<bool>& visited, vector<int>& temp_res, vector<vector<int>>& res)
{
if(depth == nums.size())
{
res.push_back(temp_res);
return;
}
for(int i = 0;i < nums.size();i++)
{
if(!visited[i])
{
temp_res.push_back(nums[i]);
visited[i] = true;
dfs(nums, depth + 1, visited, temp_res, res);
temp_res.pop_back();
visited[i] = false;
}
}
}
vector<vector<int>> permute(vector<int>& nums) {
vector<int> temp_res;
vector<vector<int>> res;
vector<bool> visited(nums.size(), false);
dfs(nums, 0, visited, temp_res, res);
return res;
}
};
47.全排列
题解:画出树后进行剪枝分析,即相同的元素做排列的开头会重复,应将相同元素做开头的排列只保留一支,保留的方法通过取相同元素第一次做开头和不是第一次做开头时,visited数组的区别进行剪枝。
class Solution {
public:
void dfs(vector<int>& nums, int start, vector<bool>& visited, vector<int>& path, vector<vector<int>>& res)
{
if(start == nums.size())
{
res.push_back(path);
return;
}
for(int i = 0;i < nums.size();i++)
{
if(i > 0 && nums[i - 1] == nums[i] && !visited[i - 1])
continue;
if(!visited[i])
{
path.push_back(nums[i]);
visited[i] = true;
dfs(nums, start + 1, visited, path, res);
path.pop_back();
visited[i] = false;
}
}
}
vector<vector<int>> permuteUnique(vector<int>& nums) {
vector<bool> visited(nums.size(), false);
vector<vector<int>> res;
vector<int> path;
sort(nums.begin(), nums.end());
dfs(nums, 0, visited, path, res);
return res;
}
};
39.组合总和
题解:组合数应以start作为递归对象,即选定一个数作为递归的起点时,之后能够选择的数应该是这个数往后取(包括这个数),同时,该题目中对已经排好序的数组,当选取的值大于当前target时,之后的值就不用继续选取了,结束循环后,进行以下一个数为开头的递归。
class Solution {
public:
void dfs(vector<int>& candidates, int& target, int start, vector<int>& path, vector<vector<int>>& res)
{
if(target == 0)
{
res.push_back(path);
return;
}
for(int i = start;i < candidates.size();i++)
{
if(candidates[i] > target)
break;
target -= candidates[i];
path.push_back(candidates[i]);
dfs(candidates, target, i, path, res);
path.pop_back();
target += candidates[i];
}
}
vector<vector<int>> combinationSum(vector<int>& candidates, int target)
{
sort(candidates.begin(), candidates.end());
vector<vector<int>> res;
vector<int> path;
dfs(candidates, target, 0, path, res);
return res;
}
};
40.组合总和||
题解:该题目与上题类似,只不过在组合数时需要把已经选择了的元素考虑在外,同时由于是组合数的关系,相同数做开头的组合同样应被剪去,可以通过分析需要剪枝时start的状态与不需要剪的差异,也可以加入visited数组来判断彼此的区别。两种都可:
class Solution {
public:
void dfs(vector<int>& candidates, int start, int& target, vector<int>& path, vector<vector<int>>& res)
{
if(target == 0)
{
res.push_back(path);
return;
}
for(int i = start;i < candidates.size(); i++)
{
if(i > start && candidates[i - 1] == candidates[i])
continue;
if(candidates[i] > target)
break;
target -= candidates[i];
path.push_back(candidates[i]);
dfs(candidates, i + 1, target, path, res);
target += candidates[i];
path.pop_back();
}
}
vector<vector<int>> combinationSum2(vector<int>& candidates, int target) {
sort(candidates.begin(), candidates.end());
vector<int> path;
vector<vector<int>> res;
dfs(candidates, 0 , target, path, res);
return res;
}
};
class Solution {
public:
void dfs(vector<int>& candidates, int start, int& target, vector<int>& path, vector<vector<int>>& res, vector<bool>& vistied)
{
if(target == 0)
{
res.push_back(path);
return;
}
for(int i = start;i < candidates.size(); i++)
{
if(i > 0 && candidates[i - 1] == candidates[i] && !vistied[i - 1])
continue;
if(candidates[i] > target)
break;
vistied[i] = true;
target -= candidates[i];
path.push_back(candidates[i]);
dfs(candidates, i + 1, target, path, res, vistied);
target += candidates[i];
path.pop_back();
vistied[i] = false;
}
}
vector<vector<int>> combinationSum2(vector<int>& candidates, int target) {
sort(candidates.begin(), candidates.end());
vector<int> path;
vector<vector<int>> res;
vector<bool> vistied(candidates.size(), false);
dfs(candidates, 0 , target, path, res, vistied);
return res;
}
};
77.组合
题解:组合数采用 start作为递归起始。本题中根据还需要的组合数与剩余的组合数可以优化速度。n - i +1表示剩余的数的个数,k - path.size()表示还需要的数,n - i + 1 >= k - path.size(),即i <= n + 1 - k + path.size()。
class Solution {
public:
void dfs(int n, int k, int start, vector<int>& path, vector<vector<int>>& res)
{
if(path.size() == k)
{
res.push_back(path);
return;
}
for(int i = start;i <= n + 1 - k + path.size() ; i++)
{
path.push_back(i);
dfs(n, k, i + 1, path, res);
path.pop_back();
}
}
vector<vector<int>> combine(int n, int k) {
vector<int> path;
vector<vector<int>> res;
dfs(n, k, 1, path, res);
return res;
}
};
78.子集
题解:组合数采用start作为起始进行递归,每递归一次就将结果记录至res中,直到取完。
class Solution {
public:
void dfs(vector<int>& nums, int start, vector<int>& path, vector<vector<int>>& res)
{
res.push_back(path);
if(start == nums.size())
return;
for(int i = start; i < nums.size(); i++)
{
path.push_back(nums[i]);
dfs(nums, i + 1, path, res);
path.pop_back();
}
}
vector<vector<int>> subsets(vector<int>& nums) {
vector<int> path;
vector<vector<int>> res;
dfs(nums, 0, path, res);
return res;
}
};
90.子集||
题解:剪枝,可以创建一个visited数组记录各个值的访问情况,通过对比重复的组合与需要保留的组合状态间的区别来设置剪枝条件。也可以通过start与i的情况来剪枝
class Solution {
public:
void dfs(vector<int>& nums, int start, vector<bool>& visited, vector<int>& path, vector<vector<int>>& res)
{
res.push_back(path);
if(start == nums.size())
{
return;
}
for(int i = start; i < nums.size(); i++)
{
if(i > 0 && nums[i] == nums[i - 1] && !visited[i - 1])
continue;
path.push_back(nums[i]);
visited[i] = true;
dfs(nums, i + 1, visited, path, res);
visited[i] = false;
path.pop_back();
}
}
vector<vector<int>> subsetsWithDup(vector<int>& nums) {
sort(nums.begin(), nums.end());
vector<int> path;
vector<vector<int>> res;
vector<bool> visited(nums.size(), false);
dfs(nums, 0, visited, path, res);
return res;
}
};
class Solution {
public:
void dfs(vector<int>& nums, int start, vector<int>& path, vector<vector<int>>& res)
{
res.push_back(path);
if(start == nums.size())
{
return;
}
for(int i = start; i < nums.size(); i++)
{
if(i > start && nums[i - 1] == nums[i])
continue;
path.push_back(nums[i]);
dfs(nums, i + 1, path, res);
path.pop_back();
}
}
vector<vector<int>> subsetsWithDup(vector<int>& nums) {
sort(nums.begin(), nums.end());
vector<int> path;
vector<vector<int>> res;
dfs(nums, 0 , path, res);
return res;
}
};
60.排列序列
题解:该题的难点在于找到n,res.size()以及k值对应的关系,主要考虑n - res.size()的阶乘与k的大小关系,即如果jc(n - res.size())的值大于k说明以当前数作为开头的字符串的数量中包含了所要找的结果,如果小于则说明不在这之中,需要跟换一个开头数字,同时将原开头数字下排列字符串的个数减去,并用引用传递k值。
class Solution {
public:
int jc(int n)
{
if(n == 0) return 1;
int sum = 1;
for(int i = 1;i<=n;i++)
{
sum = sum * i;
}
return sum;
}
void dfs(int n, int& k, vector<bool>& visited, string &res, bool &find)
{
if(res.size() == n)
{
find = true;
return;
}
for(int i = 1;i <= n && !find; i++)
{
if(jc(n - res.size()) < k)
{
k -= jc(n - res.size());
break;
}
if(!visited[i])
{
res += to_string(i);
visited[i] = true;
dfs(n, k, visited, res, find);
if(!find){
res.pop_back();
visited[i] = false;
}
}
}
}
string getPermutation(int n, int k) {
string res;
vector<bool> visited(n + 1, false);
bool find = false;
dfs(n, k, visited, res, find);
return res;
}
};
93.复原ip地址
题解:ip地址包含4段每段不超过3个字符,因此横向遍历时取得值应在3个以内,同时注意取值与start的关系,保证递归时能够取到想要取到的值。在取好值后,判断所取得值是否合法,合法则继续向下递归。递归结束的条件是s中的值被全部取完,且ip地址的尺寸为4。
class Solution {
public:
string getstr(vector<int>& path)
{
string str;
for(int i = 0;i<path.size();i++)
{
str += to_string(path[i]);
str += '.';
}
str.pop_back();
return str;
}
int to_int(string str)
{
int sum = 0;
for(int i = 0;i<str.size();i++)
{
sum = sum * 10 + str[i] - '0';
}
return sum;
}
bool valid(string &temp_str)
{
if(temp_str[0] == '0' && temp_str.size() > 1)
return false;
int sum = 0;
for(int i = 0;i<temp_str.size();i++)
{
sum = temp_str[i] + sum * 10 - '0';
}
if(sum >= 0 && sum <= 255)
return true;
return false;
}
void dfs(string &s, int start, vector<int>& path, vector<string>& res)
{
if(start == s.size() && path.size() == 4)
{
string sub_res = getstr(path);
res.push_back(sub_res);
return;
}
for(int i = start;i < start + 3 && i < s.size();i++)
{
string temp_str = s.substr(start, i - start + 1);
if(valid(temp_str))
{
path.push_back(to_int(temp_str));
dfs(s, i + 1, path, res);
path.pop_back();
}
}
}
vector<string> restoreIpAddresses(string s)
{
vector<string> res;
if(s.size() < 4 || s.size() > 12)
return res;
vector<int> path;
dfs(s, 0, path, res);
return res;
}
};
22.括号生成
题解:生成的括号组合应保证:左括号开头,右括号结尾,左括号的数量时刻大于等于右括号的数量,直到括号数量都为n结束。
class Solution {
public:
void dfs(int n, int left, int right, string path, vector<string>& res)
{
if(left < right)
return;
if(left == n && right == n)
{
res.push_back(path);
return;
}
if(left < n)
{
path += '(';
dfs(n ,left + 1, right, path, res);
path.pop_back();
}
if(right < n)
{
path += ')';
dfs(n, left, right + 1, path, res);
path.pop_back();
}
}
vector<string> generateParenthesis(int n) {
vector<string> res;
string path;
int left = 0, right = 0;
dfs(n, left, right, path, res);
return res;
}
};