题目
给定一个字符串列表 sentence
,表示一个句子,其中每个单词可以包含数字、小写字母和美元符号 $
。如果单词的形式为美元符号后跟着一个非负实数,那么这个单词就表示一个价格。我们需要在价格的基础上减免给定的 discount%
,并更新该单词到句子中。所有更新后的价格应该表示为一个恰好保留小数点后两位的数字。
示例
示例 1:
- 输入:
sentence = "there are $1 $2 and 5$ candies in the shop"
,discount = 50
- 输出:
"there are $0.50 $1.00 and 5$ candies in the shop"
示例 2:
- 输入:
sentence = "1 2 $3 4 $5 $6 7 8$ $9 $10$"
,discount = 100
- 输出:
"1 2 $0.00 4 $0.00 $0.00 7 8$ $0.00 $10$"
提示
1 <= sentence.length <= 105
sentence
由小写英文字母、数字、’ ’ 和 ‘$’ 组成sentence
不含前导和尾随空格sentence
的所有单词都用单个空格分隔- 所有价格都是正整数且不含前导零
- 所有价格最多为10位数字
0 <= discount <= 100
解决方案
我们需要遍历整个句子,并检查每个单词是否是一个价格。如果是价格,则计算折扣后的新价格并替换原来的价格。以下是实现步骤:
- 遍历句子:使用指针遍历句子,查找每个价格单词。
- 判断是否为价格:判断单词是否以
$
开头,且其后跟随的字符是数字。 - 计算折扣:对价格进行折扣计算,并格式化为保留两位小数。
- 构建新句子:将处理后的句子重新拼接起来。
很烦,很多特殊处理,像上班处理需求一样。
代码实现
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
char* discountPrices(char* sentence, int discount) {
size_t len = strlen(sentence);
// 为结果分配足够大的内存,防止只有一个'$'+一位数的情况导致溢出
char* result = malloc(len * 3);
if (result == NULL) {
return NULL;
}
char* res_ptr = result;
char* p = sentence;
while (p < sentence + len) {
// 查找下一个 '$' 符号
char* price = strstr(p, "$");
if (price) {
// 将 '$' 之前的文本复制到结果中
while (p < price) {
*res_ptr++ = *p++;
}
// 检查 '$' 后的字符是否是数字
if (price > sentence && *(price - 1) != ' ') {
// 如果 '$' 前面的字符不是空格,将 '$' 复制到结果中并继续
*res_ptr++ = *price++;
p = price;
continue;
}
if (!isdigit(*(price + 1))) {
// 如果 '$' 后的字符不是数字,直接复制 '$' 并继续
*res_ptr++ = *p++;
continue;
}
// 提取并处理价格
p = price + 1;
double double_price = 0;
char* end_of_price = p;
while (isdigit(*end_of_price) || *end_of_price == '.') {
end_of_price++;
}
// 检查价格是否紧跟非数字字符,如果是,则复制原始文本并继续
if (*end_of_price != ' ' && *end_of_price != '\0') {
while (price < end_of_price) {
*res_ptr++ = *price++;
}
p = end_of_price;
continue;
}
char original_price[20] = {0};
strncpy(original_price, price, end_of_price - price);
original_price[end_of_price - price] = '\0'; // 将复制的字符串以 '\0' 结尾
sscanf(original_price, "$%lf", &double_price);
if (double_price == 0) {
// 如果价格为 0,直接复制原始文本并继续
p = end_of_price;
while (*p && *p != ' ') {
*res_ptr++ = *p++;
}
continue;
}
// 计算折扣后的价格
double_price *= (1 - discount / 100.0);
// 格式化新的价格字符串
char new_price[20] = {0};
sprintf(new_price, "$%.2f", double_price);
size_t new_price_len = strlen(new_price);
// 将新的价格复制到结果缓冲区
memcpy(res_ptr, new_price, new_price_len);
res_ptr += new_price_len;
p = end_of_price;
} else {
// 如果没有找到更多的价格,将剩余的文本复制到结果中
while (*p) {
*res_ptr++ = *p++;
}
break;
}
}
*res_ptr = '\0';
// 如果结果字符串长度小于等于原句子长度,将结果复制回原句子缓冲区
if (strlen(result) <= len) {
strcpy(sentence, result);
free(result);
return sentence;
} else {
// 如果结果过长,重新分配内存并返回新的缓冲区
char* new_sentence = realloc(sentence, strlen(result) + 1);
if (new_sentence == NULL) {
printf("realloc failed");
return NULL;
}
strcpy(new_sentence, result);
free(result);
return new_sentence;
}
}
详细解析
-
内存分配:
result
分配了len * 3
的内存空间,以确保处理后的字符串有足够的空间存储。
-
查找价格单词:
- 使用
strstr
查找$
符号,判断其后是否跟随数字。
- 使用
-
处理价格单词:
- 提取价格部分并进行折扣计算,结果保留两位小数。
- 处理非价格部分的单词,直接复制到结果中。
-
字符串拼接:
- 将处理后的字符串拼接起来,并根据结果长度选择合适的缓冲区返回。
复杂度分析
- 时间复杂度:O(n),其中 n 为字符串长度,需要遍历每个字符。
- 空间复杂度:O(n),用于存储处理后的字符串。