小美的字符串变换(卡码网周赛第二十一期(23年美团笔试真题))

小美的字符串变换(卡码网周赛第二十一期(23年美团笔试真题))

题目描述

小美拿到了一个长度为 n 的字符串,她希望将字符串从左到右平铺成一个矩阵(先平铺第一行,然后是第二行,以此类推,矩阵有 x 行 y 列,必须保证 x * y=n,即每 y 个字符换行,共 x 行)。
该矩阵的权值定义为这个矩阵的连通块数量。小美希望最终矩阵的权值尽可能小,你能帮小美求出这个最小权值吗?
注:我们定义,上下左右四个方向相邻的相同字符是连通的。

输入

第一行输入一个正整数 n(1 <= n <= 10^4),代表字符串的长度。
第二行输入一个长度为 n 的、仅由小写字母组成的字符串。

输出

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

样例输入

9
aababbabb

样例输出

2

提示

平铺为 3 * 3 的矩阵:
aab
abb
abb
共有 2 个连通块,4 个 a 和 5 个 b。

题解1(C++版本)


#include<bits/stdc++.h>
using namespace std;

const int N = 1e4 + 10;
const int dx[] = {0, 1, -1, 0};
const int dy[] = {1, 0, 0, -1};

char s[N];
int n, Width, Lenth;
bool vis[N];

struct node{
    int x, y;
}now;


bool check(int x, int y){
    if(x <= 0 || x > Lenth || y <= 0 || y > Width || (x - 1)*Width + y <= 0 || (x - 1)*Width + y > n || vis[(x - 1)*Width + y]) return false;
    return true;
}
void bfs(int x, int y){
    
    queue<node> q;
    vis[(x - 1)*Width + y] = 1;
    q.push({x, y});
    while(!q.empty()){
        now = q.front(); q.pop();
        char c = s[(now.x - 1)*Width + now.y];
        
        for(int i = 0; i < 4; i++){
            int tx = now.x + dx[i];
            int ty = now.y + dy[i];
            
            if(!check(tx, ty) || s[(tx - 1)*Width + ty] != c) continue;
            
            vis[(tx - 1)*Width + ty] = 1;
            q.push({tx, ty});
        }
    }
}
/*
8
aabaabab 针对 2 * 4 与 4 * 2 这两种情况来讲,长宽分别是2,4,但连通块数量却不同
1、 aaba 有6个连通块
    abab
2、 aa 有4个连通块
    ba
    ab
    ab 
*/
int main(){
    scanf("%d%s", &n, s + 1);
    int ans = n;
    for(int i = 1; i <= n; i++){
        int sum = 0;
        
        if(i*(n/i)==n){ // 长与宽可以构成一个长方形
            memset(vis, 0, sizeof vis);
            Lenth = i;
            Width = n/i;
            for(int lenth = 1; lenth <= Lenth; lenth++){
                for(int width = 1; width <= Width; width++){
                    if(!vis[(lenth - 1)*Width + width]){
                        bfs(lenth, width);
                        sum++;
                    }
                    
                }
            }
            ans = min(ans, sum);
        }
    }
    printf("%d\n", ans);
    return 0;
}
  • 12
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值