繁体   English   中英

字符串格式化的时间优化:通过在单词之间添加空格将行填充为长度K

[英]Time optimization for string formatting: pad a line to length K by adding spaces between words

我已经编写了使用空格键将字符串扩展到长度K的代码。 我的代码可以运行,但是对于冗长的字符串来说不够快。 我对代码进行优化的尝试还不够,因此不胜感激。

例:

Input:
16
i love apples
Output:
i   love  apples

如果K = BUFSIZE,则目标是在1秒内进行任何字符串处理。

这是代码:

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

#define BUFSIZE 1000005

int main(void) {
    char s = ' ';
    char str[BUFSIZE], res[BUFSIZE] = "";
    int K;
    scanf("%d\n", &K);
    fgets(str, BUFSIZE, stdin);
    int i, j = 0, len = strlen(str) - 1, maxP = 0, p = 0, c = 0, sum = 0;
    if (K == len) {
        printf("%s", str);
        return 0;
    }
    for (i = 0; i < len; i++) {
        if (str[i] == s) {
            p++;
            sum++;
        }
        else if (str[i] != s && i - 1 >= 0 && str[i - 1] == s) {
            if (p > maxP) {
                maxP = p;
                p = 0;
            }
            else {
                p = 0;
            }
            c++;
        }
    }
    i = 0;
    K -= len;
    do {
        if (str[i] == s) {
            res[j] = s;
            p++;
            j++;
            i++;
        }
        else if (str[i] != s && i - 1 >= 0 && str[i - 1] == s) {
            if (sum / c == maxP && K > 0) {
                res[j] = s;
                K--;
                j++;
            }
            if (p < maxP && K > 0) {
                sum++;
                res[j] = s;
                K--;
                j++;
                p = 0;
            }
            res[j] = str[i];
            i++;
            j++;
        }
        else {
            res[j] = str[i];
            i++;
            j++;
        }
        if (i == len) {
            i = 0;
            j = 0;
            strcpy(str, res);
            len = strlen(str);
            strcpy(res, "");
        }
    } while (K > 0);
    if (i < len) {
        while (i < len) {
            res[j] = str[i];
            i++;
            j++;
        }
    }
    printf("%s", res);
    return 0;
}

我在Android手机上运行,​​因此我不在此处发布代码,但会给您一些提示。

首先,您不需要一一插入空格。 您可以创建一个字符串数组,将句子分成单词数组并存储它们。

现在您有了字数。 你可以用一个非常简单的整数除法来确定每一个“字分开”应该有多少空间有,还有多少剩余空间从左至右增加。

您已经全部完成了。 现在,您可以连接单词并在连接期间添加空格。 整个过程可以在O(N)的时间内完成,其中N是原始字符串的长度。

大多数线性算法应该是足够快在这种情况下。 性能可能是由I / O限制。

这里是一个简单O(n)的算法,以垫的线与空间与宽度:

  1. 发现通过描述在输入行的字数/([ ]*[^ ]*)*/正则表达式:

     size_t count_words(const char* str) { size_t count = 0; for ( ; ; ) { // ([ ]*[^ ]*)* for ( ; *str && *str == ' '; ++str) ; // skip separator if (!*str) break; ++count; // found word for ( ; *str && *str != ' '; ++str) ; // skip word chars } return count; } 
  2. 发现所需的空间总数知道期望的线宽度和字(非空格)在输入的字符数:

     size_t count_nonspaces(const char* str) { size_t count = 0; for ( ; *str; ++str) if (*str != ' ') ++count; return count; } 
  3. 它可以找到的单词之间的空格所需的号码。 如果空间不能均匀的话,则剩余部分由左到右插在必要时通过字与字之间调整的空间分布

  4. 从源到目的地的插入字之间的空格所计算的数目的主循环拷贝的话:

     int main(void) { const size_t max_width = 1000005; assert (max_width <= (SIZE_MAX - 2)); // read desired width, line size_t width, len; char *line; if (!(line = malloc(max_width + 2)) // '\\n' + '\\0' || !fgets(line, max_width + 2, stdin) // read 1st line || sscanf(line, "%zu", &width) != 1 || width > max_width || !fgets(line, max_width + 2, stdin) // read 2nd line || !(len = strlen(line)) // last char is always '\\n' || line[len-1] != '\\n') { exit(EXIT_FAILURE); //NOTE: let OS free memory hereafter } if (len > width) { // input line is wide enough fputs(line, stdout); // output as is exit(EXIT_SUCCESS); } // pad *line* to *width* with spaces, normalize space line[--len] = '\\0'; // chop newline const size_t word_count = count_words(line); // total number of spaces const size_t m = width - count_nonspaces(line); // number of spaces between words const size_t space_count = word_count > 1 ? m / (word_count - 1) : m; // the rest of spaces size_t rest = word_count > 1 ? m % (word_count - 1) : 0; // insert spaces between words char *str = line, *dest = malloc(width + 1); if (!dest) exit(EXIT_FAILURE); char *start = dest, *end = dest + width; for ( ; ; ) { // ([ ]*[^ ]*)* for ( ; *str == ' '; ++str) ; // skip separator // copy found word for ( ; *str && *str != ' '; ++str) *dest++ = *str; if (dest == end) { *dest = '\\0'; break; } // append spaces size_t nspaces = space_count; if (rest) { // distribute the rest of spaces: one for each word from // left to right --rest; ++nspaces; } memset(dest, ' ', nspaces); dest += nspaces; } puts(start); } 

范例

$ cc *.c && ./a.out <<<$'16\n i love apples'
i   love  apples

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM