You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

C语言实现含a/b字符串三等分最大可能性求解技术问询

解决思路与C语言实现

首先,你的方向是对的——总'a'的数量必须能被3整除是核心前提,否则直接返回0。递归在这里其实不是最优解,因为我们不需要实际划分字符串,只需要统计符合条件的划分点数量,用线性遍历+统计的方法更高效,也更容易理清边界条件。

核心逻辑拆解

我们分三种情况处理:

  • 字符串长度不足3:直接返回0,因为无法分成三个非空部分。
  • 总'a'数为0(全是'b'):此时问题转化为在n-1个间隙中选2个作为划分点,组合数公式是C(n-1, 2) = (n-1)*(n-2)/2,比如输入"bbbbb"(n=5),计算得4*3/2=6,和示例一致。
  • 总'a'数是3的倍数(设为3k,k>0):我们需要找到两个关键的划分范围:
    • 第一部分:从字符串开头到某个位置i,恰好包含k个'a',且i后面至少留2个字符(给第二、第三部分)。
    • 第二部分:从i+1到某个位置j,恰好包含k个'a',且j后面至少留1个字符(给第三部分)。
      总划分数 = 第一部分合法i的数量 × 第二部分合法j的数量。

具体实现步骤

基础版本(嵌套遍历,易理解)

先写一个容易理解的版本,用嵌套遍历统计合法划分点:

#include <stdio.h>
#include <string.h>

int countPartitions(char *s) {
    int len = strlen(s);
    if (len < 3) return 0;

    // 统计总'a'的数量
    int total_a = 0;
    for (int i = 0; i < len; i++) {
        if (s[i] == 'a') total_a++;
    }

    // 总'a'数不能被3整除,直接返回0
    if (total_a % 3 != 0) return 0;

    // 全是'b'的情况,计算组合数
    if (total_a == 0) {
        return (len - 1) * (len - 2) / 2;
    }

    int k = total_a / 3;
    int total = 0;
    int current_a = 0;

    // 遍历第一个划分点的所有可能位置
    for (int i = 0; i < len - 2; i++) {
        if (s[i] == 'a') current_a++;
        // 当第一部分恰好有k个'a'时,统计第二部分的合法划分点
        if (current_a == k) {
            int second_a = 0;
            int second_count = 0;
            for (int j = i + 1; j < len - 1; j++) {
                if (s[j] == 'a') second_a++;
                if (second_a == k) {
                    second_count++;
                }
            }
            total += second_count;
        }
    }

    return total;
}

// 测试示例
int main() {
    printf("%d\n", countPartitions("ababa"));  // 输出4
    printf("%d\n", countPartitions("bbbbb")); // 输出6
    printf("%d\n", countPartitions("ababb")); // 输出0
    return 0;
}

优化版本(线性时间,高效)

对于长字符串,嵌套遍历效率较低,我们可以提前记录所有'a'的位置,直接计算合法划分点的范围:

#include <stdio.h>
#include <string.h>
#include <stdlib.h>

int countPartitions(char *s) {
    int len = strlen(s);
    if (len < 3) return 0;

    int total_a = 0;
    for (int i = 0; i < len; i++) {
        if (s[i] == 'a') total_a++;
    }

    if (total_a % 3 != 0) return 0;
    if (total_a == 0) {
        return (len - 1) * (len - 2) / 2;
    }

    int k = total_a / 3;
    // 记录所有'a'的索引位置
    int *a_indices = (int*)malloc(total_a * sizeof(int));
    int idx = 0;
    for (int i = 0; i < len; i++) {
        if (s[i] == 'a') {
            a_indices[idx++] = i;
        }
    }

    // 计算第一部分合法i的数量:从第k个'a'的前一个位置到第k-1个'a'的位置
    int first_start = a_indices[k-1];
    int first_end = a_indices[k] - 1;
    // 确保i后面至少留2个字符
    if (first_end > len - 3) first_end = len - 3;
    int first_count = first_end - first_start + 1;

    // 计算第二部分合法j的数量:从第2k个'a'的前一个位置到第2k-1个'a'的位置
    int second_start = a_indices[2*k -1];
    int second_end = a_indices[2*k] - 1;
    // 确保j后面至少留1个字符
    if (second_end > len - 2) second_end = len - 2;
    int second_count = second_end - second_start + 1;

    free(a_indices);
    return first_count * second_count;
}

int main() {
    printf("%d\n", countPartitions("ababa"));  // 输出4
    printf("%d\n", countPartitions("bbbbb")); // 输出6
    printf("%d\n", countPartitions("ababb")); // 输出0
    return 0;
}

为什么不推荐递归?

递归的思路会让你陷入"划分后处理子串"的循环,但实际上我们只需要统计划分点的数量,不需要实际拆分字符串。递归不仅会带来额外的栈开销,还容易在边界条件(比如字符串长度不足、划分点位置合法判断)上出错,不如直接统计高效清晰。

内容的提问来源于stack exchange,提问作者Ryan

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.11 08:46:28