[英]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)的算法,以墊的線與空間與寬度:
發現通過描述在輸入行的字數/([ ]*[^ ]*)*/
正則表達式:
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; }
發現所需的空間總數知道期望的線寬度和字(非空格)在輸入的字符數:
size_t count_nonspaces(const char* str) { size_t count = 0; for ( ; *str; ++str) if (*str != ' ') ++count; return count; }
它可以找到的單詞之間的空格所需的號碼。 如果空間不能均勻的話,則剩余部分由左到右插在必要時通過字與字之間調整的空間分布
從源到目的地的插入字之間的空格所計算的數目的主循環拷貝的話:
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.