题目
给定一个字符串列表 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),用于存储处理后的字符串。