1003相连的1
题目描述
对于一个01矩阵A,求其中有多少片连成一片的1. 每个1可以和上下左右的1相连.
请为下面的Solution类实现解决这一问题的函数countConnectedOnes,函数参数A为给出的01矩阵,A的行数和列数均不大于1000. 函数的返回值是问题的答案.
class Solution {
public:
int countConnectedOnes(vector<vector<char>>& A) {
}
};
例1:
A=
100
010
001
答案为3.
例2:
A=
1101
0101
1110
答案为2.
解题思路
考查BFS,通过BFS寻找一个点所连接的所有点,queue记录同一层的节点。
解题代码
#include <iostream>
#include <vector>
#include <queue>
#include <algorithm>
using namespace std;
class Node{
public:
int x;
int y;
Node(int i,int j){x=i;y=j;}
};
class Solution {
public:
//定义四个方向
int dir[4][2]={ {0, 1}, {1, 0}, {0, -1}, {-1, 0} };
bool isValid(vector<std::vector<char> >&A,Node &node){
int m=A.size();
int n=A[0].size();
if (node.x<0 || node.x>=m ) return false;
if (node.y<0 || node.y>=n ) return false;
if (A[node.x][node.y]!='1') return false;
return true;
}
void BFS(vector<vector<char> >&A,vector<vector<bool> >&B,Node &node){
queue<Node>que;
que.push(node);
B[node.x][node.y]=true;
while(!que.empty()){
Node p = que.front();
que.pop();
for (int i = 0; i < 4; ++i)
{
Node pNext=Node(p.x+dir[i][0],p.y+dir[i][1]);
// if (Vw == Vd){//找到终点了!
// //把路径记录,这里没给出解法
// return true;//返回
// }
if (isValid(A,pNext)&&B[pNext.x][pNext.y]==false ){
que.push(pNext);
B[pNext.x][pNext.y]=true;
}
}
}
}
int countConnectedOnes(vector<vector<char> >& A) {
//空数组
int m=A.size();
if (m==0) return 0;
int n=A[0].size();
if(n==0) return 0;
//初始化节点访问矩阵
vector<std::vector<bool> > B(m,std::vector<bool> (n,false) );
int count=0;
for (int i = 0; i < m; ++i)
{
for (int j = 0; j < n; ++j)
{
if(A[i][j]=='1' && B[i][j]==false){
count ++;
Node node=Node(i,j);
BFS(A,B,node);
}
}
}
return count;
}
};
int main()
{
vector<vector<char> >migong(3,vector<char>(4));
migong[0][0]='1';migong[0][1]='1';migong[0][2]='0';migong[0][3]='1';
migong[1][0]='0';migong[1][1]='1';migong[1][2]='0';migong[1][3]='1';
migong[2][0]='1';migong[2][1]='1';migong[2][2]='1';migong[2][3]='0';
Solution sol;
int res=sol.countConnectedOnes(migong);
cout << "result is ->"<<res << endl;
return 0;
}
1004 isDAG?
题目描述
在图论中,如果一个有向图从任意顶点出发无法经过若干条边回到该点,则这个图是一个有向无环图(Directed Acyclic Graph,DAG). 对于一个n个节点的有向图(节点编号从0到n-1),请判断其是否为有向无环图.
图的节点数和边数均不多于100000.
请为下面的Solution类实现解决上述问题的isDAG函数,函数参数中n为图的节点数,edges是边集,edges[i]表示第i条边从edges[i].first指向edge[i].second. 如果是有向无环图返回true,否则返回false.
class Solution {
public:
bool isDAG(int n, vector<pair<int, int>>& edges) {
}
};
例1:
n = 3,edges = {(0, 1), (0, 2)},函数应返回true.
例2:
n = 2,edges = {(0, 1), (1, 0)},函数应返回false.
注意:你只需要提交Solution类的代码,你在本地可以编写main函数测试程序,但不需要提交main函数的代码. 注意不要修改类和函数的名称.
解题思路
先建立图的vector结构,再dfs检索有向图中有没有环
解题代码
class Solution {
public:
bool isDAG(int n, vector<pair<int, int>>& edges) {
//构造图向量-有向图
std::vector< std::vector<int> > graph(n);
for (int i = 0; i < edges.size(); ++i)
{
graph[edges[i].first].push_back(edges[i].second);
}
//记录已访问节点
std::vector<bool> visited(n,false);
//记录当前路径上的节点
std::vector<bool> onpath(n,false);
//遍历所有的图中节点,判断当前有没有回路
for (int i = 0; i < n; ++i)
{
if(has_circle(graph,i,visited,onpath))
return false;
}
return true;
}
bool has_circle(std::vector<std::vector<int> > &graph, int node,std::vector<bool> &visited,std::vector<bool> &onpath ){
if (visited[node]) return false;
onpath[node]=visited[node]=true;
for (int i = 0; i < graph[node].size(); ++i)
{
//onpath是指向路径上的节点--回路;has_circle是dfs思想
if(onpath[ graph[node][i] ]|| has_circle(graph,graph[node][i],visited,onpath) )
return true;
}
onpath[node]=false;
return false;
}
};
1005相邻的数
题目描述
从数列A[0], A[1], A[2], ..., A[N-1]中选若干个数,要求相邻的数不能都选,也就是说如果选了A[i], 就不能选A[i-1]和A[i+1]. 求能选出的最大和.
1 <= N <= 100000, 1 <= A[i] <= 1000
请为下面的Solution类实现解决上述问题的函数maxSum,函数参数A是给出的数列,返回值为所求的最大和.
class Solution {
public:
int maxSum(vector<int>& A) {
}
};
例1:A = {2, 5, 2},答案为5.
例2:A = {2, 5, 4},答案为6.
解题思路
动态规划题目,写出状态转移方程即可
解题代码
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
class Solution {
public:
int maxSum(vector<int>& A) {
if (A.size()==0 ) return 0;
std::vector<int> f(A.size());
f[0]=A[0];
f[1]=A[0]>A[1]?A[0]:A[1];
for (int i = 2; i < A.size(); ++i)
{
//
f[i]=f[i-1]>(A[i]+f[i-2])?f[i-1]:(A[i]+f[i-2]);
}
return f[A.size()-1];
}
};
int main(int argc, char const *argv[])
{
Solution sol;
cout<<"-------------------------------------------"<<endl;
int arr1[]={2,5,2}; int arr2[]={2,5,4};
vector<int>A(begin(arr1),end(arr1));
vector<int>B(begin(arr2),end(arr2));
cout<<"solutionA is :"<<sol.maxSum(A)<<endl;
cout<<"solutionB is :"<<sol.maxSum(B)<<endl;
// cout<<"solution is :"<<sol.F(2,3)<<endl;
// cout<<"solution is :"<<sol.F(10,10)<<endl;
cout<<"-------------------------------------------"<<endl;
return 0;
}
1006单词变换
题目描述
对于两个只含有小写英文字母(’a’-‘z’)的单词word1和word2,你可以对word1进行以下3种操作:
1) 插入一个字母;
2) 删除一个字母;
3) 替换一个字母.
请计算将word1变换成word2的最少操作数.
word1和word2的长度均不大于1000.
请为下面的Solution类实现解决上述问题的函数minDistance,函数的参数word1和word2为给出的两个单词,返回值为所求最少操作数.
class Solution {
public:
int minDistance(string word1, string word2) {
}
};
例1:word1 = “sunny”, word2 = “snowy”,返回值为3.
例2:word1 = “abc”, word2 = “ac”,返回值为1.
解题思路
经典动规。
使用一个二维数组dp[m][n] 来维护状态,它表示从一个长度为m的word1变换到一个长度为n的word2所需要的最少操作数。
每次将两个单词往前看一个字母,那么有如下两种可能。
两个字母相同。那么,显然不需要做更改操作,有 dp[m][n] = dp[m - 1][n - 1]
两个字母不相同,那么,需要考虑如下三种操作:
如果word1的当前字母和word2的前一个字母相同,那么说明word1需要做1次插入操作,即dp[m][n] = 1 + dp[m][n - 1];
如果word1的前一个字母和word2的当前字母相同,那么说明word1需要做1次删除操作,即dp[m][n] = 1 + dp[m - 1][n];
如果word1的前一个字母和word2的前一个字母相同,那么说明word1需要做1次替换操作,即dp[m][n] = 1 + dp[m - 1][n].
由于要找的是最小的操作次数,所以,在第二种情况下,取三种子情况的最小值。
解题代码
class Solution {
public:
int triMin(int a, int b, int c) {
int tempA = min(a, b);
int tempB = min(b, c);
return min(tempA, tempB);
}
int minDistance(string word1, string word2) {
int m = word1.size();
int n = word2.size();
int dp[m + 1][n + 1];
for (int i = 0; i <= m; ++i) {
for (int j = 0; j <= n; ++j) {
if (i == 0) dp[i][j] = j;
else if (j == 0) dp[i][j] = i;
else if (word1[i - 1] == word2[j - 1])
dp[i][j] = dp[i - 1][j - 1];
else
dp[i][j] = 1 + triMin(dp[i][j - 1], // insert
dp[i - 1][j], // remove
dp[i - 1][j - 1]); // replace
}
}
return dp[m][n];
}
};