C语言 优化二进制字符串拆分以获得最大分数

5t7ly7z5  于 2024-01-06  发布在  其他
关注(0)|答案(2)|浏览(127)

我是C语言的初学者,一直在尝试Leet代码的问题:

*Problem Statement: 给定一个0和1的字符串s,返回将字符串拆分为两个非空子串(即左子串和右子串)后的最大得分。

拆分字符串后的分数是左子串中的0的数量加上右子串中的1的数量 *

这是我的尝试:

c language
int maxScore(char* s) {
    int length=strlen(s);
    //int count_zero=0;
    int arr[length];
    int s_zero=0;
    int s_one=0;
    int sum=0;
    
    for(int n=0;n<length;n++)
    {
        for(int i=0;i<=n;i++)
        {
            if(s[i]=='0')
            {
                s_zero+=1;
            }
        }

        for(int j=n+1;j<length;j++)
        {
            if(s[j]=='1')
            {
                s_one+=1;
            }
        }

        sum=s_zero+s_one;
        arr[n]=sum;
        s_zero=0;
        s_one=0;
        sum=0;
    }

    int ans=arr[0];

    for(int i=0;i<length-1;i++)
    {
        for(int j=i+1;j<length;j++)
        {
            if(arr[i]>arr[j] && arr[i]>ans)
            {
                ans=arr[i];
            }
        }
    }

    return ans;

}

字符串
它已经通过了测试用例(100/104),但是当输入是'110000'时,它没有通过测试用例。它给出的输出是1而不是3。请告诉我我的代码哪里出错了。请记住,我是一个初学者,现在才开始接触C语言。

7vhp5slm

7vhp5slm1#

  1. for(int n=0;n<length;n++)应该是n < length - 1,因为在n=length-1处拆分无效。
    1.(可选)使用单独的循环来对左右分区进行评分是非常好的,但是组合起来,它们会扫描所有的s,因此可以在单个循环中通过计算分割前的0(包括)n和分割后的1(不包括)。
    1.(次要)在初始化ans = arr[0]时,for(int i=0;i<length-1;i++)可以从i=1开始。
  2. for(int j=i+1;j<length;j++)不正确,因为arr[length-1]不是有效的拆分(根据% 1.)。
    1.要找到一个数组的最大值ans,你只需要遍历它一次(O(n))。你有什么工作(除了4.),但它不必要地慢(O(n^2))。
    合并将以上所有内容结合起来,重新命名变量以供通用(n通常用于长度,ij作为索引变量),您将得到此O(n^2)算法:
int maxScore(const char *s) {
    int n = strlen(s);
    int ans = 0;
    for(int i=0; i < n-1; i++) {
       int score = 0;
       for(int j = 0; j < n; j++)
           score += (j <= i && s[j] == '0') + (j > i && s[j] == '1');
       if(score > ans) ans = score;
    }
    return ans;
}

字符串
另一种方法是在数组zero中从左边开始累加0的计数。左边分区的分数是zero[i]。右边位置的分数有n-i-1个数字(0或1),所以我们需要减去有zero[n-1] - zero[i]的0来找出有多少个1。这有O(n)的运行时间:

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

size_t maxScore(const char *s) {
    size_t n = strlen(s);
    if(n < 2) return -1; // error

    size_t zero[n];
    zero[0] = s[0] == '0';
    for(size_t i = 1; i < n; i++)
        zero[i] = zero[i-1] + (s[i] == '0');

    size_t max = 0;
    for(size_t i = 0; i < n - 1; i++) {
        size_t score = zero[i] + (n - i - 1 - zero[n-1] - zero[i]);
        if(score > max) max = score;
    }
    return max;
}

int main(void)  {
    printf("%zu\n", maxScore("110000"));
}


两种实现的输出都是:

3

64jmpszr

64jmpszr2#

作为对Allan Wind的完整回答的补充,这里有一个替代实现。
我们的想法是先遍历字符串,确定其长度,并计算零的数量(如果左边的子串可能是整个字符串,则等于分数)。然后将拆分移动到左边,同时根据移动到右边子串的元素的值更新分数:

unsigned maxScore(const char *s)
{
    unsigned score = 0;
    unsigned n = 0;
    while(s[n] != 0)
    {
        if(s[n] == '0') score++;
        n++;
    }
    unsigned scoreMax = 0;
    while(n >= 2)
    {
        n--;
        if(s[n] == '0') score--;
        if(s[n] == '1') score++;
        if(score > scoreMax) scoreMax = score;
    }
    return scoreMax;
}

字符串

相关问题