简体   繁体   English

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

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

I have written code to extend string to length K using spacebar symbol. 我已经编写了使用空格键将字符串扩展到长度K的代码。 My code works, but is not fast enough for lengthy strings. 我的代码可以运行,但是对于冗长的字符串来说不够快。 My tries at optimizing the code were insufficient, so any help would be appreciated. 我对代码进行优化的尝试还不够,因此不胜感激。

Example: 例:

Input:
16
i love apples
Output:
i   love  apples

The goal is to make any string process in 1 second, if K = BUFSIZE. 如果K = BUFSIZE,则目标是在1秒内进行任何字符串处理。

Here is the code: 这是代码:

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

I'm running on an Android phone so I'm not posting code here, but I'll give you some hint. 我在Android手机上运行,​​因此我不在此处发布代码,但会给您一些提示。

First, you don't need to insert spaces one-by-one. 首先,您不需要一一插入空格。 You can create an array of strings, separate the sentence into an array of words and store them. 您可以创建一个字符串数组,将句子分成单词数组并存储它们。

Now you have the number of words. 现在您有了字数。 You can use a very simple integer division to determine how many spaces should every "word separation" have, as well as how many remaining spaces to be added from left to right. 你可以用一个非常简单的整数除法来确定每一个“字分开”应该有多少空间有,还有多少剩余空间从左至右增加。

You've done all of them. 您已经全部完成了。 You can now concatenate the words and add the spaces during concatenation. 现在,您可以连接单词并在连接期间添加空格。 The whole procedure can be done in a time of O(N), where N is the length of the original string. 整个过程可以在O(N)的时间内完成,其中N是原始字符串的长度。

Most linear algorithms should be fast enough in this case. 大多数线性算法应该是足够快在这种情况下。 The performance is likely limited by I/O. 性能可能是由I / O限制。

Here's a straightforward O(n) algorithm to pad a line to width with spaces: 这里是一个简单O(n)的算法,以垫的线与空间与宽度:

  1. find number of words in the input line described by /([ ]*[^ ]*)*/ regex: 发现通过描述在输入行的字数/([ ]*[^ ]*)*/正则表达式:

     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. find total number of spaces required knowing the desired line width and the number of word (nonspace) characters in the input: 发现所需的空间总数知道期望的线宽度和字(非空格)在输入的字符数:

     size_t count_nonspaces(const char* str) { size_t count = 0; for ( ; *str; ++str) if (*str != ' ') ++count; return count; } 
  3. it allows to find the desired number of spaces between words. 它可以找到的单词之间的空格所需的号码。 If spaces can't be evenly distributed between words then the remainder is inserted from left to right by adjusting the space between words if necessary 如果空间不能均匀的话,则剩余部分由左到右插在必要时通过字与字之间调整的空间分布

  4. the main loop copies words from the source to destination inserting the computed number of spaces between words: 从源到目的地的插入字之间的空格所计算的数目的主循环拷贝的话:

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

Example : 范例

$ 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