代码随想录算法训练营第 50 天 |98. 所有可达路径

代码随想录算法训练营

Day50 代码随想录算法训练营第 50 天 |98. 所有可达路径



前言

LeetCode98. 所有可达路径

讲解文档


一、图论基础概念

1、图的种类

整体上一般分为 有向图 和 无向图

2、度

(1)无向图中有几条边连接该节点,该节点就有几度
(2)在有向图中,每个节点有出度和入度。

出度:从该节点出发的边的个数。

入度:指向该节点边的个数。

例如,该有向图中,节点3的入度为2,出度为1,节点1的入度为0,出度为2

3、连通性:节点的连通情况

(1)连通图
在无向图中,任何两个节点都是可以到达的的图为连通图
(如果有节点不能到达其他节点,则为非连通图)
(2)强连通图
在有向图中,任何两个节点是可以相互到达的为强连通图
(3)连通分量
在无向图中的极大连通子图称之为该图的一个连通分量
(4) 强连通分量
在有向图中极大强连通子图称之为该图的强连通分量
代码随想录-强连通分量 代码随想录-强连通分量

  • 节点1、节点2、节点3、节点4、节点5 构成的子图是强连通分量,因为这是强连通图,也是极大图。

  • 节点6、节点7、节点8 构成的子图 不是强连通分量,因为这不是强连通图,节点8 不能达到节点6。

  • 节点1、节点2、节点5 构成的子图 也不是 强连通分量,因为这不是极大图-

4、图的构造

(1)邻接矩阵

邻接矩阵 使用 二维数组来表示图结构。 邻接矩阵是从节点的角度来表示图,有多少节点就申请多大的二维数组
例如:
有向图:grid[2][5] = 6 表示 节点2 指向 节点5,边的权值为6
无向图:grid[2][5] = 6,grid[5][2] = 6,表示节点2 与 节点5 相互连通,权值为6
(2)邻接表
邻接表 使用 数组 + 链表的方式来表示。 邻接表是从边的数量来表示图,有多少边 才会申请对应大小的链表
代码随想录-邻接表代码随想录-邻接表

  • 节点1 指向 节点3 和 节点5
  • 节点2 指向 节点4、节点3、节点5
  • 节点3 指向 节点4
  • 节点4指向节点1

5、图的遍历方式

(在邻接表或邻接矩阵上进行搜索)
(1)深度优先搜索(dfs)–递归实现
(2) 广度优先搜索(bfs)

二、深度优先搜索

1、深度优先搜索的三部曲

(1)确认递归函数,参数
深搜需要 二维数组数组结构保存所有路径,需要一维数组保存单一路径,可以定义一个全局变量,避免函数参数过多
(2)确认终止条件
(3) 处理目前搜索节点出发的路径
一个for循环的操作,去遍 目前搜索节点所能到的所有节点;
加入路径,递归调用,弹出

2、深度优先搜索框架

void dfs(参数) {
    if (终止条件) {
        存放结果;
        return;
    }

    for (选择:本节点所连接的其他节点) {
        处理节点;
        dfs(图,选择的节点); // 递归
        回溯,撤销处理结果
    }
}


三、LeetCode98. 所有可达路径

1.题目链接

LeetCode98. 所有可达路径

2.思路

(1)存图:
link[i][k]=1:指的是有i指向k的路径
(2)深度优先搜索
1)返回值:void
参数:终点,遍历到第几个点(当前点的下标),存图的数组
2)终止条件
当前遍历点下标等于终点下标
3)处理目前搜索节点出发的路径
① 遍历当前节点(下标i)对应的link[i]数组,如果link[i][k]等于1,那么i–>k路径存在
② k加入路径
③ k进行递归调用
④ k弹出路径

3.题解

#include<bits/stdc++.h>
using namespace std;
vector<vector<int>>ans ;
vector<int>path;

void dfs(int i,int n,vector<vector<int>>link)
{
    if(i==n)
    {
        ans.push_back(path);
        return ;
    }
    for(int k=1;k<=n;k++)
    {   
        if(link[i][k])
        {
            path.push_back(k);
            dfs(k,n,link);
            path.pop_back();
        }
    }
    
}
int main()
{
    int n;
    int m;
    int t1;
    int t2;
    cin>>n>>m;
    vector<vector<int>>link(n+1,vector<int>(n+1,0));
    //下标表示的点所连接的点的集合
    for(int i=0;i<m;i++)
    {
        
        cin>>t1>>t2;
      
        link[t1][t2]=1;//t1--->t2
    }
    path.push_back(1);
    dfs(1,n,link);
   
    int l=ans.size();
    if(l==0)
    {
        cout<<-1<<"\n";
    }else
    {
        for(int i=0;i<l;i++)
        {
            int r=ans[i].size();
            for(int j=0;j<r;j++)
            {
                cout<<ans[i][j];
                if(j<r-1)cout<<" ";
                if(j==r-1)cout<<"\n";
            }
        }
    }
    
    return 0;
    
}

总结

第二十二算法训练营主要涵盖了Leetcode题目中的三道题目,分别是Leetcode 28 "Find the Index of the First Occurrence in a String",Leetcode 977 "有序数组的平方",和Leetcode 209 "长度最小的子数组"。 首先是Leetcode 28题,题目要求在给定的字符串中找到第一个出现的字符的索引。思路是使用双指针来遍历字符串,一个指向字符串的开头,另一个指向字符串的结尾。通过比较两个指针所指向的字符是否相等来判断是否找到了第一个出现的字符。具体实现的代码如下: ```python def findIndex(self, s: str) -> int: left = 0 right = len(s) - 1 while left <= right: if s[left == s[right]: return left left += 1 right -= 1 return -1 ``` 接下来是Leetcode 977题,题目要求对给定的有序数组中的元素进行平方,并按照非递减的顺序返回结果。这里由于数组已经是有序的,所以可以使用双指针的方法来解决问题。一个指针指向数组的开头,另一个指针指向数组的末尾。通过比较两个指针所指向的元素的绝对值的大小来确定哪个元素的平方应该放在结果数组的末尾。具体实现的代码如下: ```python def sortedSquares(self, nums: List[int]) -> List[int]: left = 0 right = len(nums) - 1 ans = [] while left <= right: if abs(nums[left]) >= abs(nums[right]): ans.append(nums[left ** 2) left += 1 else: ans.append(nums[right ** 2) right -= 1 return ans[::-1] ``` 最后是Leetcode 209题,题目要求在给定的数组中找到长度最小的子数组,使得子数组的和大于等于给定的目标值。这里可以使用滑动窗口的方法来解决问题。使用两个指针来表示滑动窗口的左边界和右边界,通过移动指针来调整滑动窗口的大小,使得滑动窗口中的元素的和满足题目要求。具体实现的代码如下: ```python def minSubArrayLen(self, target: int, nums: List[int]) -> int: left = 0 right = 0 ans = float('inf') total = 0 while right < len(nums): total += nums[right] while total >= target: ans = min(ans, right - left + 1) total -= nums[left] left += 1 right += 1 return ans if ans != float('inf') else 0 ``` 以上就是第二十二算法训练营的内容。通过这些题目的练习,可以提升对双指针和滑动窗口等算法的理解和应用能力。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值