【daily practice】最长数字串怎么找?岛屿数量如何沉岛秒数?六棍拼两三角形有几种验法?(5.字符串中找出连续最长的数字串、岛屿数量、拼三角)

字符串中找出连续最长的数字串、岛屿数量、拼三角

文章目录


1. 字符串中找出连续最长的数字串

🔗 题目链接 | 难度:🟢 Easy

问题描述

text 复制代码
读入一个字符串 str,输出该字符串中连续最长的数字串。

输入描述:
一个测试输入包含 1 个测试用例,一个字符串 str,长度不超过 255。

输出描述:
在一行内输出 str 中连续最长的数字串。

示例:
输入:abcd12345ed125ss123456789
输出:123456789

题目解法

解法一:

思路:

​ 滑动数组,不多赘述

Bug: 代码审查 --- 边界条件

  • 问题 :当输入字符串不含任何数字时,resl=resr=0r-lresr-resl 均为 0,最终 substr(0, 1) 会输出首字符而非空串,属于边界遗漏。
  • 建议 :初始化 resr = -1 使 resr - resl + 1 = 0 时输出空串;或在最后添加特判 if (resr < resl) 直接返回。
    复杂度分析:时间复杂度 O(n),空间复杂度 O(1)。一次线性遍历,仅用常数变量维护窗口起止位置。
cpp 复制代码
int main() {
    int resl = 0, resr = 0;
    int l = 0, r = 0;
    string str;
    cin >> str;
    bool is_num = false;
    for(int i = 0; i < str.size(); ++i)
    {
        if(str[i] >= '0' && str[i] <= '9')
        {
            if(is_num)
                r++;
            else
            {
                //处理上次的数组
                if(r - l > resr - resl)
                {
                    resl = l;
                    resr = r;
                }
                l = r = i;
                is_num = true;
            }
        }
        else
            is_num = false;
    }
    //处理上次的数组
    if(r - l > resr - resl)
    {
        resl = l;
        resr = r;
    }
    cout << str.substr(resl, resr - resl + 1);
}

错误记录

要点总结

  • 滑动窗口 / 双指针 :维护 [l, r] 区间标记当前连续数字串,遇到非数字时暂存、遇到新数字串时比较长度更新最优解。
  • 字符判断c >= '0' && c <= '9' 是判断数字字符的可移植写法,也可用 isdigit() 标准库函数。
  • 边界处理:遍历结束后需额外处理最后一组数字串;注意输入不含数字时的空串输出。
  • 空间效率:原地 O(1) 空间扫描是最优方案,无需额外数组。

2. 岛屿数量

🔗 题目链接 | 难度:🟡 Medium

问题描述

text 复制代码
给定一个 m × n 的二维网格,其中 '1' 表示陆地,'0' 表示海洋。
如果两个 '1' 相邻(上下左右四个方向,不包含斜对角),则它们属于同一个岛屿。
请计算网格中岛屿的总数量。

数据范围:1 ≤ n, m ≤ 200
进阶:空间复杂度 O(nm),时间复杂度 O(nm)

示例 1:
输入:
[
[1,1,0],
[1,1,0],
[0,0,1]
]
输出:2

示例 2:
输入:
[
[1,0,1],
[0,1,0],
[1,0,1]
]
输出:5

题目解法

解法一:

思路:

思路说明

BFS 洪水填充。遍历网格每个格子,遇到 '1' 即计数 +1,并以该点为起点进行 BFS:将相连的所有 '1' 标记为 '0'(沉岛),完成一个岛屿的统计。重复直至所有格子遍历完毕。

复杂度分析:时间 O(m×n)(每个格子访问一次),空间 O(min(m, n))(BFS 队列最大长度)。

cpp 复制代码
class Solution {
public:
    using PII = pair<int, int>;
    int dx[4] = {0, 0, 1, -1};
    int dy[4] = {1, -1, 0, 0};

    int solve(vector<vector<char> >& grid) {
        int xsize = grid.size();
        if(!xsize) return 0;
        int ysize = grid[0].size();
        if(!ysize) return 0;

        int count = 0;
        for(int sx = 0; sx < xsize; ++sx)
        {
            for(int sy = 0; sy < ysize; ++sy)
            {
                if(grid[sx][sy] == '0')
                    continue;
                count++;
                queue<PII> q;
                q.push({sx, sy});
                grid[sx][sy] = '0';
                while(!q.empty())
                {
                    int x = q.front().first;
                    int y = q.front().second;
                    q.pop();
                    for(int i = 0; i < 4; ++i)
                    {
                        int m = x + dx[i];
                        int n = y + dy[i];
                        if(m >= 0 && m < xsize && n >=0 && n < ysize && grid[m][n] == '1')
                        {
                            q.push({m, n});
                            grid[m][n] = '0';
                        }
                    }
                }
            }
        }
        return count;
    }
};
解法二:DFS(深度优先搜索)

思路:

使用递归替代队列进行深度优先搜索,代码更简洁。同样采用"沉岛"策略,将已访问陆地标记为 '0'

cpp 复制代码
class Solution {
public:
    void dfs(vector<vector<char>>& grid, int i, int j) {
        if (i < 0 || i >= grid.size() || j < 0 || j >= grid[0].size() || grid[i][j] == '0')
            return;
        grid[i][j] = '0';  // 沉岛
        dfs(grid, i - 1, j);
        dfs(grid, i + 1, j);
        dfs(grid, i, j - 1);
        dfs(grid, i, j + 1);
    }

    int solve(vector<vector<char>>& grid) {
        if (grid.empty() || grid[0].empty()) return 0;
        int count = 0;
        for (int i = 0; i < grid.size(); ++i) {
            for (int j = 0; j < grid[0].size(); ++j) {
                if (grid[i][j] == '1') {
                    ++count;
                    dfs(grid, i, j);
                }
            }
        }
        return count;
    }
};

复杂度分析:时间 O(m×n),空间 O(m×n)(最坏递归栈深度为整个网格)。

错误记录

要点总结

  • FloodFill 算法:从一个种子点出发,通过 BFS/DFS 遍历所有连通节点,标记访问("沉岛")避免重复计数。
  • BFS vs DFS:BFS 用队列实现,无栈溢出风险;DFS 代码更简洁。本题两种均可。
  • 方向数组dx[4] = {0,0,1,-1}, dy[4] = {1,-1,0,0} 简化四个方向的遍历。
  • 原地标记 :将已访问的 '1' 修改为 '0',无需额外 visited 数组(前提是允许修改原数组)。

3. 拼三角

🔗 题目链接 | 难度:🟢 Easy

问题描述

text 复制代码
给出 6 根棍子,每根棍子有长度。问是否能取其中的 3 根拼成一个三角形,
并且剩下的 3 根也能拼成一个三角形?

输入描述:
第一行一个整数 T,表示数据组数(1 ≤ T ≤ 10)。
对于每组数据,输入一行 6 个整数,表示每根棍子的长度(1 ≤ 长度 ≤ 100)。

输出描述:
对于每组数据,如果可以拼成两个三角形,输出 "Yes",否则输出 "No"。

示例:
输入:
2
1 1 1 1 1 1
1 2 3 4 5 6
输出:
Yes
No

题目解法

解法一:

思路:

思路说明 :暴力枚举。三层循环 i < j < k 枚举所有 C(6,3) = 20 种取 3 根棍子的组合,验证是否能构成三角形。若能,再验证剩余 3 根是否能构成三角形。一旦找到合法分组即返回 true

复杂度分析:时间 O(20) ≈ O(1)(常数次枚举),空间 O(1)。6 根棍子规模极小,暴力枚举即可。

cpp 复制代码
bool fun(vector<int>& bar)
{
    for(int i = 0; i < 4; ++i)
    {
        for(int j = i + 1; j < 5; j++)
        {
            for(int k = j + 1; k < 6; ++k)
            {
                if(bar[k] + bar[j] > bar[i] &&
                    bar[i] + bar[k] > bar[j] &&
                    bar[i] + bar[j] > bar[k] 
                )
                {
                    vector<int> bar2;
                    for(int l = 0; l < 6; ++l)
                    {
                        if(l != i && l != j && l != k)
                            bar2.push_back(bar[l]);
                    }
                    if(bar2[1] + bar2[2] > bar2[0] &&
                        bar2[0] + bar2[2] > bar2[1] &&
                        bar2[0] + bar2[1] > bar2[2] 
                    )
                        return true;
                }
            }
        }
    }
    return false;
}

int main() {
    int n;
    cin >> n;
    while(n--)
    {
        vector<int> bar;
        for(int i = 0; i < 6; ++i)
        {
            int x;
            cin >> x;
            bar.push_back(x);
        }
        
        if(fun(bar))
            cout << "Yes" << endl;
        else
            cout << "No" << endl;
    }
}
解法二:排序 + 4 种固定分组

思路:

先将 6 根棍子排序。观察发现,将排序后的 6 根棍子分成两组(每组 3 根),所有可能的分组方式可以归纳为 4 种固定模式。只需检查这 4 种分组是否各能构成三角形即可,无需暴力枚举所有组合。

cpp 复制代码
bool canFormTriangle(int a, int b, int c) {
    // 排序后,只需检查 a + b > c(c 为最大边)
    return a + b > c;
}

bool fun(vector<int>& bar) {
    sort(bar.begin(), bar.end());
    // 检查 4 种固定分组(排序后归纳可得,覆盖所有可能)
    // 组合1: (0,1,2) + (3,4,5)
    if (canFormTriangle(bar[0], bar[1], bar[2]) &&
        canFormTriangle(bar[3], bar[4], bar[5]))
        return true;
    // 组合2: (0,2,3) + (1,4,5)
    if (canFormTriangle(bar[0], bar[2], bar[3]) &&
        canFormTriangle(bar[1], bar[4], bar[5]))
        return true;
    // 组合3: (0,3,4) + (1,2,5)
    if (canFormTriangle(bar[0], bar[3], bar[4]) &&
        canFormTriangle(bar[1], bar[2], bar[5]))
        return true;
    // 组合4: (0,4,5) + (1,2,3)
    if (canFormTriangle(bar[0], bar[4], bar[5]) &&
        canFormTriangle(bar[1], bar[2], bar[3]))
        return true;
    return false;
}

复杂度分析 :时间 O(1)(常数次比较),空间 O(1)。排序 O(6 log 6) 可视为常数。

相较于暴力枚举 20 种组合的 O(20) 时间,两者均为常数级,但排序法代码更简洁,思路更清晰。

错误记录

要点总结

  • 暴力枚举:6 根棍子选 3 根,仅 C(6,3) = 20 种组合,暴力枚举即可,无需复杂算法。
  • 三角形判定:排序后只需判断最短两边之和 > 最长边,全排列的三个不等式可简化为一个。
  • 枚举技巧 :三层循环 i < j < k 保证不重不漏;剩余 3 根棍子同样验证三角形条件。
相关推荐
Bernice橘子1 小时前
职场英语学习计划Day040
学习
疯狂打码的少年1 小时前
【数据结构】排序算法:归并排序与基数排序
数据结构·笔记·算法·排序算法
橙橙笔记2 小时前
Python学习第三部分
开发语言·python·学习
weixin_431600442 小时前
Agent Workflow 学习向:最小拖拽画布,看得见地编排,再一键跑通
后端·学习·ai·dify
LuminousCPP2 小时前
嵌入式-51单片机入门(三)-数码管驱动:从单管点亮、多位扫描到动态刷新与消隐原理
笔记·单片机·嵌入式硬件·51单片机
小柯博客3 小时前
01 · 点亮 STM32MP25 的硬件视频编解码:VPU 与那些“安静“的坑
c语言·笔记·stm32·单片机·嵌入式硬件·嵌入式·视频编解码
欧叶冲冲冲3 小时前
uv Python 环境管理笔记
笔记·python·uv
自小吃多3 小时前
Capture软件原理图PDF输出笔记
笔记·嵌入式硬件
很楠爱上3 小时前
从“AI 看合同”到可举证的合同决策链:CounterClause(对薄) 的架构设计与工程实践
人工智能·经验分享·python·学习·agent