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

文章目录

  • 【DFS/BFS】美团20230812秋招T5-小美的字符串变换
  • 题目描述与示例
    • 题目描述
    • 输入描述
    • 输出描述
    • 示例
      • 输入
      • 输出
      • 说明
  • 解题思路
  • 代码
    • 解法一:DFS
      • Python
      • Java
      • C++
  • 解法二:BFS
    • 时空复杂度
  • 华为OD算法/大厂面试高频题算法练习冲刺训练

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

题目描述与示例

题目描述

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

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

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

输入描述

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

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

1<=n<=10^4

输出描述

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

示例

输入

9
aababbabb

输出

2

说明

平铺为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)

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));
    }
}

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;
}

解法二: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了解更多

你可能感兴趣的:(大厂秋招真题,#,DFS,#,BFS,深度优先,宽度优先,算法)