【无标题】

简要复习了bfs,dfs

DFS(深度优先搜索)是一种递归或者栈结构实现的搜索算法,可以用于无权图或者有权图(边权值相等)。

算法步骤如下:

  1. 初始化一个标记数组 visited,表示每个节点是否已被访问;
  1. 从起始节点开始,递归访问它的所有未被访问过的邻居节点。
int visited[100];        // 标记节点是否已访问

void dfs(int u, int n) 
{
    visited[u] = 1;            // 标记节点 u 已被访问
    printf("%d ", u);          // 访问节点 u
    for (int v = 0; v < n; v++)// 遍历节点 u 的所有邻居节点 v
     {   
        if (graph[u][v] && !visited[v]) // 如果存在边 uv,且 v 未被访问过
        {  
            dfs(v, n);      // 递归访问节点 v
    }
    }
}

BFS(广度优先搜索)是一种逐层扫描搜索算法,可以用于无权图或者有权图(边权值相等)。

算法步骤如下:

  1. 初始化一个标记数组 visited 和一个队列 queue,将起始节点标记为已访问,并将其入队;
  1. 当队列非空时,取出队首节点,遍历它的所有邻居节点:若邻居节点未被访问,则标记为已访问并入队;
  1. 重复步骤2,直到队列为空。
int graph[10][10]; // 邻接矩阵存储图
int visited[100];        // 标记节点是否已访问
int duilie[100];          // 队列

void chushihuaGraph(int n)// 初始化邻接矩阵
{
        for (int i = 0; i < n; i++) 
        {
            for (int j = 0; j < n; j++) 
            {
                graph[i][j] = 0;
            }
        }
    
}

void bfs(int start, int n) 
{
    int head = 0, tail = 0;
    
    visited[start] = 1;       // 起始节点已经访问过,标记为已访问
    
    duilie[tail++] = start;   // 将起始节点加入队列

    while (head < tail)       // 队列非空
    {    
        int u = duilie[head++];   // 取出队首节点
        
        printf("%d ", u);        // 访问节点 u
        
        for (int v = 0; v < n; v++) // 遍历所有邻居节点
        {   
            if (graph[u][v] && !visited[v]) // 如果存在边 uv,且 v 未被访问过
            {   
                visited[v] = 1;      // 标记节点 v 已被访问
                duilie[tail++] = v;  // 将节点 v 加入队列
            }
        }
    }
}

1010. 总持续时间可被 60 整除的歌曲

难度中等

259

在歌曲列表中,第 i 首歌曲的持续时间为 time[i] 秒。

返回其总持续时间(以秒为单位)可被 60 整除的歌曲对的数量。形式上,我们希望下标数字 i 和 j 满足  i < j 且有 (time[i] + time[j]) % 60 == 0。

示例 1:

输入:time = [30,20,150,100,40]输出:3解释:这三对的总持续时间可被 60 整除:(time[0] = 30, time[2] = 150): 总持续时间 180(time[1] = 20, time[3] = 100): 总持续时间 120(time[1] = 20, time[4] = 40): 总持续时间 60

示例 2:

输入:time = [60,60,60]输出:3解释:所有三对的总持续时间都是 120,可以被 60 整除

看题先想到遍历解决,但是在时间上需求过高,容易时间超限。

int numPairsDivisibleBy60(int* time, int timeSize)
{
int count = 0;

for(int i = 0 ; i < timeSize ; i ++)
for(int j = timeSize - 1 ; j > i ; j --)
{

if((time[i] + time[j]) % 60 == 0)
{
    count ++;
}

}

return count ;
}

然后根据官方题解:

组合数学

思路

需要返回其总持续时间(以秒为单位)可被 6060 整除的歌曲对的数量,因此,每首歌曲对结果的影响因素是它的持续时间除以 6060 后的余数。可以用一个长度为 6060 的数组 \textit{cnt}cnt,用来表示余数出现的次数。然后分情况统计歌曲对:

余数为 00 的歌曲。他们需要与余数为 00 的歌曲组成对,但不能与自己组成对。歌曲对的数量为 \textit{cnt}[0] \times (\textit{cnt}[0]-1)/2cnt[0]×(cnt[0]−1)/2。

余数为 3030 的歌曲。他们需要与余数为 3030 的歌曲组成对,但不能与自己组成对。歌曲对的数量为 \textit{cnt}[30] \times (\textit{cnt}[30]-1)/2cnt[30]×(cnt[30]−1)/2。

余数为 i, i\in[1,29]i,i∈[1,29] 的歌曲。他们需要与余数为 60-i60−i 的歌曲组成对。歌曲对的数量为 \sum_{i=1}^{29}\textit{cnt}[i] \times \textit{cnt}[60-i]∑

i=1

29

cnt[i]×cnt[60−i]。

余数为 i, i\in[31,59]i,i∈[31,59] 的歌曲。已经在上一部分组对过,不需要重复计算。

把这几部分求和,就可以得到最后的对数。

额,还要注意数据提供的范围,需要longlong型数据来执行,否侧测试数据会超出范围。

int numPairsDivisibleBy60(int* time, int timeSize) 
{
    long long count[60]={0},num=0;

    memset(count , 0 , sizeof(count));

    for (int i = 0; i < timeSize; i++) 
    {
        count[time[i] % 60] ++;
    }

    for (int i = 1; i < 30; i++) 
    {
        num += count[i] * count[60 - i];  //两两组合相乘即可
    }
    
    //理解为Cn2
    num +=(long long)(count[0] *  (count[0] - 1)  / 2);
    num +=(long long)(count[30] * (count[30] - 1) / 2);

    return num;
}

还有一种题解,感觉和官解差不多,但感觉更好理解

使用哈希表来进行优化。

具体来说,我们可以遍历一遍歌曲列表,对于每首歌曲的持续时间 time[i],计算其除以 60 的余数 num1。然后在哈希表中查找是否存在 60 - num1 的键值对,若存在,则将对应值加入计数器 count 中。

int numPairsDivisibleBy60(int* time, int timeSize){
    int count = 0;
    int jishu[60] = {0};
    for (int i = 0; i < timeSize; i++)
     {
        int num1 = time[i] % 60;
        int num2 = (60 - num1) % 60;
        count += jishu[complement];
        jishu[remainder]++;
    }
    
    return count;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值