题目描述:
🔗leetocde 2288. 价格减免
句子 是由若干个单词组成的字符串,单词之间用单个空格分隔,其中每个单词可以包含数字、小写字母、和美元符号 ‘$’
。如果单词的形式为美元符号后跟着一个非负实数,那么这个单词就表示一个 价格 。给你一个字符串 sentence。表示一个句子和一个整数 discount 。对于每个表示价格的单词,都在价格的基础上减免 discount% ,并更新该单词到句子中。所有更新后的价格应该表示为一个 恰好保留小数点后两位 的数字。
返回表示修改后句子的字符串。
注意:所有价格 最多为 10 位数字。
示例 1:
输入:sentence = “there are $1 2 a n d 5 2 and 5 2and5$ candies in the shop”, discount = 50
输出:“there are $0.50 1.00 a n d 5 1.00 and 5 1.00and5$ candies in the shop” 解释: 表示价格的单词是"$1" 和 “$2” 。
- “$1” 减免 50% 为 “$0.50” ,所以 “$1” 替换为 “$0.50” 。
- “$2” 减免 50% 为 “$1” ,所以 “$1” 替换为 “$1.00” 。
方法一:
由于每个单词之间都存在空格,通过上述描述我们很容易想到以空格将字符串分离成字符串数组然后遍历每个单词,找到满足以 ‘$’ 开头,后面都是数字的单词然后修改价格即可。
定义 x 为原价,那么折扣价为 :
x - discount / 100.0 * x = x * (1 - discount / 100.0)
java 代码
class Solution {
public String discountPrices(String sentence, int discount) {
String[] words = sentence.split(" ");
for (int i = 0; i < words.length; i++) {
String word = words[i];
if (word.charAt(0) == '$' && isPrice(word.substring(1))) {
double price = Long.parseLong(word.substring(1)) * (1 - discount / 100.0);
words[i] = String.format("$%.2f", price);
}
}
StringBuilder sb = new StringBuilder();
for (int i = 0; i < words.length; i++) {
if (i > 0) {
sb.append(" ");
}
sb.append(words[i]);
}
return sb.toString();
}
public boolean isPrice(String s) {
for (int i = 0; i < s.length(); i ++ ) {
if (!Character.isDigit(s.charAt(i))) {
return false;
}
}
return true;
}
}
C++ 代码
class Solution {
public:
string discountPrices(string sentence, int discount) {
stringstream sin(sentence), sout;
sout << fixed << setprecision(2);
vector<string> words;
string word;
while (sin >> word) {
if (word[0] == '$' && word.size() > 1 && all_of(word.begin() + 1, word.end(), ::isdigit)) {
double price = stoll(word.substr(1, word.size() - 1)) * (1.0 - discount / 100.0);
sout << '$' << price;
}
else {
sout << word;
}
sout << " ";
}
string ans = sout.str();
ans.pop_back();
return ans;
}
};
方法二:
考虑另外的一种方法,不对字符串进行分离,从0开始枚举每个字符,由于每个单词之间都有空格进行分离。我们可以枚举前后空格去查询单词是否为价格。定义 [i, j) 表示某个单词的左闭右开的区间,i - 1 和 j 分别指向前后的空格,那么只需要找到满足 sentence[i] = ‘$’, sentence[j] == 空格,并且中间都是数字的单词就可以了。
为什么不用搜索前面的空格而是搜索 $ 符号呢?因为如果当前单词是价格的话,它一定以 $ 开头,而 $ 字符前面就是空格。
考虑一般情况,我们用 i 枚举字符串的索引去找到 $ 字符 ,然后判断第 i + 1 个字符是否为数字,如果不是,则不需要在继续搜索后面的数字。如果是,定义 j = i + 1去枚举后面的数字即可。
上面是一般情况,正常情况是我们还需要考虑第一个单词和最后一个单词的情况。
也就是满足:
if (i == 0 || sentence[i - 1] == ' ') && (j == sentence.size() || sentence[j] == ' ')
C++ 代码
class Solution {
public:
string discountPrices(string sentence, int discount) {
for (int i = 0; i < sentence.size(); i ++ ) {
char ch = sentence[i];
int n = sentence.size();
if (ch == '$' && isdigit(sentence[i + 1])) {
int j = i + 1;
long long x = 0;
while (j < n && isdigit(sentence[j])) {
x = x * 10 + sentence[j] - '0';
j ++;
}
if ((i == 0 || sentence[i - 1] == ' ') && (j == n || sentence[j] == ' ')) {
double price = x - (discount / 100.0 * x);
stringstream ss;
ss << fixed << setprecision(2) << price;
string str = ss.str();
sentence.replace(i + 1, j - i - 1, str);
i += str.size();
}
}
}
return sentence;
}
};
java 代码
class Solution {
public String discountPrices(String sentence, int discount) {
StringBuilder str = new StringBuilder(sentence);
for (int i = 0; i < str.length() - 1; i ++ ) {
if (str.charAt(i) == '$') {
int j = i + 1;
while (j < str.length() && isDigit(str.charAt(j)) && j - i <= 10) j ++;
if ((i == 0 || str.charAt(i - 1) == ' ') && (j == str.length() || str.charAt(j) == ' ')) {
String priceStr = str.substring(i + 1, j);
long x = Long.parseLong(priceStr);
double price = x - discount / 100.0 * x;
String format = String.format("%.2f", price);
str.replace(i + 1, j, format);
i += format.length();
}
}
}
return str.toString();
}
private boolean isDigit(char ch) {
return ch >= '0' && ch <= '9';
}
}