代码随想录算法训练营day47

5 阅读4分钟

有向图的访问

1.对于深度优先遍历的设计不熟悉,什么时候该递归,什么时候该终止,很多思考没有弄明白 2.对于邻接表图应用并不熟练,很多粗疏的地方,比如应该事先同样申请n+1的空间。 3.visit传参应当使用引用,同时应该注意是bool类型还是int类型

#include<iostream>
#include<vector>
#include<list>
using namespace std;

// 深度优先搜索:标记从key出发能到达的所有节点
// 参数:graph(邻接表,引用传递避免复制)、visit(访问标记,引用传递)、key(当前节点)
void dfs(vector<list<int>>& graph, vector<bool>& visit, int key) {
    // 标记当前节点为已访问
    visit[key] = true;
    // 获取当前节点的邻接表(引用避免复制)
    list<int>& neighbors = graph[key];
    // 遍历所有邻接节点
    for (int next_node : neighbors) {
        if (!visit[next_node]) {  // 仅访问未访问的节点
            dfs(graph, visit, next_node);
        }
    }
}

int main() {
    // 输入节点数量n、边的数量k
    cout << "输入结点数量和边的数量(空格分隔):" << endl;
    int n, k;
    cin >> n >> k;

    // 初始化邻接表:大小为n+1(节点从1到n编号)
    vector<list<int>> graph(n + 1);
    cout << "输入" << k << "条边(每条边两个节点s t,空格分隔):" << endl;
    for (int i = 0; i < k; i++) {
        int s, t;
        cin >> s >> t;
        graph[s].push_back(t);  // 添加s→t的边
        graph[t].push_back(s);  // 【关键】如果是无向图,必须添加t→s的边;若为有向图可删除此行
    }

    // 初始化访问标记数组:大小n+1,初始值false
    vector<bool> visit(n + 1, false);
    // 从节点1开始DFS
    dfs(graph, visit, 1);

    // 检查是否所有节点都被访问
    bool all_visited = true;
    for (int i = 1; i <= n; i++) {
        if (!visit[i]) {
            all_visited = false;
            break;
        }
    }

    // 输出结果
    if (all_visited) {
        cout << 1 << endl;
    } else {
        cout << -1 << endl;
    }

    return 0;  // 正常结束返回0
}

采用bfs时怎么入队,出队要思考

#include<iostream>
#include<vector>
#include<list>
#include<queue>  // 【关键】添加queue头文件
using namespace std;

int main() {
    // 输入节点数量n、边的数量k
    cout << "输入结点数量和边的数量(空格分隔):" << endl;
    int n, k;
    cin >> n >> k;

    // 初始化邻接表:大小为n+1(节点从1到n编号)
    vector<list<int>> graph(n + 1);
    cout << "输入" << k << "条边(每条边两个节点s t,空格分隔):" << endl;
    for (int i = 0; i < k; i++) {
        int s, t;
        cin >> s >> t;
        graph[s].push_back(t);  // 添加s→t的边
        graph[t].push_back(s);  // 【关键】无向图需双向添加边;有向图可删除此行
    }

    // 初始化访问标记数组:大小n+1,初始值false
    vector<bool> visit(n + 1, false);
    // 从节点1开始BFS
    queue<int> que;
    visit[1] = true;  // 【关键】入队前先标记起始节点为已访问
    que.push(1);      // 【关键】queue入队用push(),不是push_back()

    // 执行BFS
    while (!que.empty()) {
        // 出队获取当前节点
        int key = que.front();
        que.pop();
        // 获取当前节点的邻接表(const引用避免复制)
        const list<int>& neighbors = graph[key];
        // 遍历所有邻接节点
        for (int cur : neighbors) {
            if (!visit[cur]) {  // 仅访问未访问的节点
                visit[cur] = true;  // 入队前先标记,避免重复入队
                que.push(cur);      // 入队
            }
        }
    }

    // 检查是否所有节点都被访问
    bool all_visited = true;
    for (int i = 1; i <= n; i++) {
        if (!visit[i]) {
            all_visited = false;
            break;
        }
    }

    // 输出结果
    if (all_visited) {
        cout << 1 << endl;
    } else {
        cout << -1 << endl;
    }

    return 0;  // 正常结束返回0
}

字符串问题:

1.需要运用hash表快速查找映射 2.对于传参和返回值要有考虑

//思路:将每个字符串视作一个结点,存在单个字符相互转换关系的字符串存在联通关系
//可以通过图的遍历算法求得结果,采用广度优先搜索可以最快获得最短路径,不需要多次比较
//步骤:1.将字符串映射至hash表方便快速查找
//2.通过不断变换字符串的单个字符,并在hash表中寻找联通字符串
//3.找到下一个联通字符串之后存入数组并标记,继续重复,直到查找到目标字符串或遍历完毕

#include<iostream>
#include <vector>
#include <string>
#include <unordered_set>
#include <unordered_map>
#include <queue>

using namespace std;

int main(){
    //读入字符串
    int N;
    cout<<"输入字符串数量"<<endl;
    cin>>N;
    //使用hash表存储字符串字典
    unordered_set<string> strList;
    //输入起始字符串和终止字符串
    string beginStr;
    string endStr;
    cin>>beginStr>>endStr;
    //读入字典
    string str;
    for(int i=1;i<=N;i++){
        cin>>str;
        strList.insert(str);
    }
   // 记录strSet里的字符串是否被访问过,同时记录路径长度
    unordered_map<string, int> visitMap; // <记录的字符串,路径长度>

    // 初始化队列
    queue<string> que;
    que.push(beginStr);
    //初始化visitMap,方便快速查找迭代
    visitMap.insert(pair<string, int>(beginStr, 1));
    //开始广度优先搜索
    while(!que.empty()){
        //出队
        string cur=que.front();
        que.pop();
        int path = visitMap[word]; // 这个字符串在路径中的长度
        //逐一替换字符串字符,并开始在strList中比对寻找,如果满足条件,插入visitMap中
        for(int i=0;i<cur.size();i++){
            for(int j=0;j<26;j++){
                string newWord=cur;
                //将第i个字符替换
                newWord[i]=j+'a';
                //判断是否为endStr
                 if (newWord == endStr) { // 发现替换字母后,字符串与终点字符串相同
                    cout <<  path + 1 << endl; // 找到了路径 
                    return 0;
                }
                //如果不是endStr,则在strList中进行比对
                if(strList.find(newWord)!=strList.end()&&visitMap.find(newWord)=visitMap.end()){//在词典中可查找到,且未被访问
                     visitMap.insert(pair<string, int>(newWord, path + 1));//插入到词典当中
                    que.push(newWord);//执行入队

                }
            }
        }
        
    }

    //循环执行完毕之后未查找到,则返回0
     cout<<0<<endl;
     return 0;
}