• 大厂秋招真题【DFS/BFS】美团20230812秋招T5-小美的字符串变换


    【DFS/BFS】美团20230812秋招T5-小美的字符串变换

    题目描述与示例

    题目描述

    小美拿到了一个长度为n的字符串,她希望将字符串从左到右平铺成一个矩阵(先平铺第一行,然后是第二行,以此类推,矩阵有xy列,必须保证x*y=n,即每y个字符换行,共x行)。

    该矩阵的权值定义为这个矩阵的连通块数量。小美希望最终矩阵的权值尽可能小,你能帮小美求出这个最小权值吗?

    注:我们定义,上下左右四个方向相邻的相同字符是连通的。

    输入描述

    第一行输入一个正整数n,代表字符串的长度。

    第二行输入一个长度为n的、仅由小写字母组成的字符串。

    1<=n<=10^4
    
    • 1

    输出描述

    输出一个整数表示最小权值。

    示例

    输入

    9
    aababbabb
    
    • 1
    • 2

    输出

    2
    
    • 1

    说明

    平铺为3*3的矩阵: aab abb abb 共有2个连通块,4a5b

    解题思路

    这个问题的需求其实是很明确的,根据题意我们需要做两件事

    1. 找到所有可以摆列的方式,需要满足x*y=n,假设其中x为小的,那么可以枚举1k(k*k=n,不需要枚举到n),找到所有的枚举方式
    2. 每一个具体的枚举,通过DFS或者BFS的方式,找到其中的联通快数量。具体实现上标记每个位置是否访问,然后从一个方块如果未访问,那么联通块+1然后向四周搜索拓展、标记。

    代码

    解法一:DFS

    Python

    # 题目:【DFS&BFS】美团2023秋招-小美的字符串变换
    # 作者:闭着眼睛学数理化
    # 算法:DFS
    # 相关习题:LeetCode200. 岛屿数量
    # 代码有看不懂的地方请直接在群上提问
    
    
    from math import inf, sqrt
    
    
    DIRECTIONS = [(0, 1), (1, 0), (0, -1), (-1, 0)]
    
    
    def dfs(grid, checkList, i, j, N, M):
        # 标记点(i, j)为已检查过
        checkList[i][j] = 1
        # 遍历四个近邻点
        for di, dj in DIRECTIONS:
            ni, nj = i+di, j+dj
            # 注意此处需要判断(ni, nj)在grid中的值,是否和(i, j)相等
            if (0 <= ni < N and 0 <= nj < M and checkList[ni][nj] == 0
                and grid[i][j] == grid[ni][nj]):
                dfs(grid, checkList, ni, nj, N, M)
    
    
    def solve(s, N, M):
        # 根据s和N、M的值,构建N行M列的字符串矩阵grid
        grid = [s[i:i+M] for i in range(0, N*M, M)]
        # 检查列表
        checkList = [[0] * M for _ in range(N)]
        # 连通块数量
        block_num = 0
        # 双重遍历
        for i in range(N):
            for j in range(M):
                # 尚未检查过的点,进行DFS
                if checkList[i][j] == 0:
                    dfs(grid, checkList, i, j, N, M)
                    # 做完DFS,连通块数量+1
                    block_num += 1
        # 返回连通块数量
        return block_num
    
    
    # 输入字符串长度n和字符串s
    n = int(input())
    s = input()
    # 初始化答案为inf
    ans = inf
    
    # 遍历从1到sqrt(N)的所有因数N
    for N in range(1, int(sqrt(n))+1):
        # 如果n能够整除N,即N是n的因数
        # 则另一个因数M = n // N
        if n % N == 0:
            M = n // N
            # 分别以N和M作为长宽、宽长,进行计算,并且更新答案
            ans = min(ans, solve(s, N, M))
            ans = min(ans, solve(s, M, N))
    
    print(ans)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61

    Java

    import java.util.*;
    
    public class Main {
        public static int minWeight(int n, String s) {
            int minW = Integer.MAX_VALUE;
            // 遍历所有可能的矩阵大小,找到所有满足x*y=n的x和y
            for (int i = 1; i*i <= n; i++) {
                if (n % i == 0) {
                    int x = i;
                    int y = n / i;
                    // 构建矩阵
                    char[][] matrix = new char[x][y];
                    for (int j = 0; j < x; j++) {
                        for (int k = 0; k < y; k++) {
                            matrix[j][k] = s.charAt(j * y + k);
                        }
                    }
                    // 计算矩阵的权值并更新最小权值
                    minW = Math.min(minW, countConnected(matrix));
                    
                    //这里面x*y=n 其中一个作为长 一个作为宽 两个情况都要考虑
                    x=n/i;
                    y=i;
                    // 构建矩阵
                    matrix = new char[x][y];
                    for (int j = 0; j < x; j++) {
                        for (int k = 0; k < y; k++) {
                            matrix[j][k] = s.charAt(j * y + k);
                        }
                    }
                    // 计算矩阵的权值并更新最小权值
                    minW = Math.min(minW, countConnected(matrix));
                }
            }
            return minW;
        }
    
        // 计算矩阵的连通块数量
        public static int countConnected(char[][] matrix) {
            int count = 0;
            boolean[][] visited = new boolean[matrix.length][matrix[0].length];
            int[][] directions = {{0, 1}, {1, 0}, {0, -1}, {-1, 0}};
    
            for (int i = 0; i < matrix.length; i++) {
                for (int j = 0; j < matrix[0].length; j++) {
                    if (!visited[i][j]) {
                        count++;
                        dfs(matrix, visited, directions, i, j);
                    }
                }
            }
            return count;
        }
    
        // 深度优先搜索连通块
        public static void dfs(char[][] matrix, boolean[][] visited, int[][] directions, int x, int y) {
            visited[x][y] = true;//标记为true 避免重复计算
            for (int[] direction : directions) {
                int nx = x + direction[0];
                int ny = y + direction[1];
                if (nx >= 0 && nx < matrix.length && ny >= 0 && ny < matrix[0].length && !visited[nx][ny] && matrix[nx][ny] == matrix[x][y]) {
                    dfs(matrix, visited, directions, nx, ny);
                }
            }
        }
    
        public static void main(String[] args) {
            Scanner scanner = new Scanner(System.in);
            int n = scanner.nextInt();
            scanner.nextLine();
            String s = scanner.nextLine();
            System.out.println(minWeight(n, s));
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74

    C++

    #include 
    #include 
    #include 
    #include  // Include this header for INT_MAX
    
    using namespace std;
    
    const vector<pair<int, int>> DIRECTIONS = {{0, 1}, {1, 0}, {0, -1}, {-1, 0}};
    
    void dfs(vector<string>& grid, vector<vector<int>>& checkList, int i, int j, int N, int M) {
        checkList[i][j] = 1;
        for (const auto& dir : DIRECTIONS) {
            int ni = i + dir.first;
            int nj = j + dir.second;
            if (ni >= 0 && ni < N && nj >= 0 && nj < M && checkList[ni][nj] == 0 && grid[i][j] == grid[ni][nj]) {
                dfs(grid, checkList, ni, nj, N, M);
            }
        }
    }
    
    int solve(string s, int N, int M) {
        vector<string> grid(N, string(M, ' '));
        vector<vector<int>> checkList(N, vector<int>(M, 0));
        int block_num = 0;
    
        for (int i = 0; i < N; ++i) {
            for (int j = 0; j < M; ++j) {
                grid[i][j] = s[i * M + j];
            }
        }
    
        for (int i = 0; i < N; ++i) {
            for (int j = 0; j < M; ++j) {
                if (checkList[i][j] == 0) {
                    dfs(grid, checkList, i, j, N, M);
                    block_num += 1;
                }
            }
        }
    
        return block_num;
    }
    
    int main() {
        int n;
        cin >> n;
        string s;
        cin >> s;
        int ans = INT_MAX;
    
        for (int N = 1; N * N <= n; ++N) {
            if (n % N == 0) {
                int M = n / N;
                ans = min(ans, solve(s, N, M));
                ans = min(ans, solve(s, M, N));
            }
        }
    
        cout << ans << endl;
        return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61

    解法二:BFS

    时空复杂度

    时间复杂度:O(Nk)N为网格大小,k为字符串变换的方法数,即N的因数个数。

    空间复杂度:O(N)

    华为OD算法/大厂面试高频题算法练习冲刺训练

    • 华为OD算法/大厂面试高频题算法冲刺训练目前开始常态化报名!目前已服务100+同学成功上岸!

    • 课程讲师为全网50w+粉丝编程博主@吴师兄学算法 以及小红书头部编程博主@闭着眼睛学数理化

    • 每期人数维持在20人内,保证能够最大限度地满足到每一个同学的需求,达到和1v1同样的学习效果!

    • 60+天陪伴式学习,40+直播课时,300+动画图解视频,300+LeetCode经典题,200+华为OD真题/大厂真题,还有简历修改、模拟面试、专属HR对接将为你解锁

    • 可上全网独家的欧弟OJ系统练习华子OD、大厂真题

    • 可查看链接 OD算法冲刺训练课程表 & OD真题汇总(持续更新)

    • 绿色聊天软件戳 od1336了解更多

  • 相关阅读:
    C# 控制台设置
    本地生活商家如何通过短视频赛道,提升销量曝光量?
    Java学习笔记 --- Collections工具类
    FastestDet为arm而生
    leetcode:774. 最小化去加油站的最大距离【经典二分check】
    ​k8s如何做容器的高可用?
    无中微子双贝塔衰变
    linux C语言 socket的server、client 实现
    LA@特征值和特征向量的性质
    Ubuntu 20.04.06 PCL C++学习记录(二十六)
  • 原文地址:https://blog.csdn.net/weixin_48157259/article/details/133814443