本周是一道简单的算法题,计算利润。我计划使用TDD的原则开发,并且换用几种不同的方法解题。
如果你没看过上一期关于TDD和gtest的文章,我推荐你去看一下地址
题目:奖金计算
题目:
企业发放的奖金根据利润提成。利润低于或等于100000元的,奖金可提10%;
利润高于100000元,低于200000元(100000<I≤200000)时,低于100000元的部分按10%提成,高于100000元的部分,可提成 7.5%;
200000<I≤400000时,低于200000元部分仍按上述办法提成,(下同),高于200000元的部分按5%提成;
400000<I≤600000元时,高于400000元的部分按3%提成;
600000<I≤1000000时,高于600000元的部分按1.5%提成;
I>1000000时,超过1000000元的部分按1%提成。
方法一:if多else if
应该是最常规的一种解法。
依然按照之前文章的结构,搭建gtest环境,各部分的代码如下:
BonusMoney.h
代码如下:
int bonus(int moneyGet);
BonusMoney.cpp
代码如下:
#include "BonusMoney.h"
int bonus(int moneyGet)
{
int bonus = 0;
if (moneyGet <= 100000)
bonus = 0.1 * moneyGet;
else if (moneyGet <= 200000)
bonus = 0.1 * 100000 + 0.075 * (moneyGet - 100000);
else if (moneyGet <= 400000)
bonus = 0.1 * 100000 + 0.075 * 100000 + 0.05 * (moneyGet - 200000);
else if (moneyGet <= 600000)
bonus = 0.1 * 100000 + 0.075 * 100000 + 0.05 * 200000 + 0.03 * (moneyGet - 400000);
else if (moneyGet <= 1000000)
bonus = 0.1 * 100000 + 0.075 * 100000 + 0.05 * 200000 + 0.03 * 200000 + 0.015 * (moneyGet - 600000);
else
bonus = 0.1 * 100000 + 0.075 * 100000 + 0.05 * 200000 + 0.03 * 200000 + 0.015 * 400000 + 0.01 * (moneyGet - 1000000);
return bonus;
}
BonusMoney_unittest.cpp
代码如下:
#include "gtest/gtest.h"
#include "BonusMoney.h"
TEST(bonusMoneyTest, moneyGet_10000)
{
EXPECT_EQ(bonus(10000), 0.1 * 10000);
}
TEST(bonusMoneyTest, moneyGet_110000)
{
EXPECT_EQ(bonus(110000), 0.1 * 100000 + 0.075 * (110000 - 100000));
}
TEST(bonusMoneyTest, moneyGet_210000)
{
EXPECT_EQ(bonus(210000), 0.1 * 100000 + 0.075 * 100000 + 0.05 * (210000 - 200000));
}
TEST(bonusMoneyTest, moneyGet_410000)
{
EXPECT_EQ(bonus(410000), 0.1 * 100000 + 0.075 * 100000 + 0.05 * 200000 + 0.03 * (410000 - 400000));
}
TEST(bonusMoneyTest, moneyGet_610000)
{
EXPECT_EQ(bonus(610000), 0.1 * 100000 + 0.075 * 100000 + 0.05 * 200000 + 0.03 * 200000 + 0.015 * (610000 - 600000));
}
TEST(bonusMoneyTest, moneyGet_1100000)
{
EXPECT_EQ(bonus(1100000), 0.1 * 100000 + 0.075 * 100000 + 0.05 * 200000 + 0.03 * 200000 + 0.015 * 400000 + 0.01 * (1100000 - 1000000));
}
int main(int argc, char **argv)
{
testing::InitGoogleTest(&argc, argv);
return RUN_ALL_TESTS();
}
方法二:switch-case
在讲这个方法的原理前,我先介绍一个switch-case
的特殊用法,也许不那么特殊。
一般来说,Switch-case
结构,每个case
中的代码都会以break
结尾,代表跳出switch
。
switch(...):
case a:
...;
break;
case b:
... ...
如果不使用break
的话,会继续按顺序执行别的case
中的代码,直到遇到下一个break
。这种现象叫穿透。我一直以为,穿透是一种需要避免的bug,但其实,它也是一种可以利用的特性。
由于穿透会执行匹配到的case后面所有的工作代码,我们可以逆向思维,从最大的情况开始匹配,最大是无限大,所以将最大的匹配放在default里;同时,为了确保范围内的数都能得到匹配(毕竟我们不能每个数都写case),我们使用/
进行范围转换:
switch (moneyGet / 100000)
{
default:
moneyGet -= 1000000;
profit += moneyGet * 0.01;
moneyGet = 1000000;
减去每个范围的利润,并累加奖金。后面就是逐个穿透了:
case 9:
case 8:
case 7:
case 6:
moneyGet -= 600000;
profit += moneyGet * 0.015;
moneyGet = 600000;
BonusMoneySwitch.cpp
完整代码如下:
int bonusSwitch(int moneyGet)
{
int profit = 0;
switch (moneyGet / 100000)
{
default:
moneyGet -= 1000000;
profit += moneyGet * 0.01;
moneyGet = 1000000;
case 9:
case 8:
case 7:
case 6:
moneyGet -= 600000;
profit += moneyGet * 0.015;
moneyGet = 600000;
case 5:
case 4:
moneyGet -= 400000;
profit += moneyGet * 0.03;
moneyGet = 400000;
case 3:
case 2:
moneyGet -= 200000;
profit += moneyGet * 0.05;
moneyGet = 200000;
case 1:
moneyGet -= 100000;
profit += moneyGet * 0.075;
moneyGet = 100000;
case 0:
profit += moneyGet * 0.1;
}
return profit;
}
对应的gtest就不全写了,仅展示一例:
TEST(bonusMoneyTest, moneyGet_1100000)
{
EXPECT_EQ(bonus(1100000), 0.1 * 100000 + 0.075 * 100000 + 0.05 * 200000 + 0.03 * 200000 + 0.015 * 400000 + 0.01 * (1100000 - 1000000));
EXPECT_EQ(bonusSwitch(1100000), 0.1 * 100000 + 0.075 * 100000 + 0.05 * 200000 + 0.03 * 200000 + 0.015 * 400000 + 0.01 * (1100000 - 1000000));
}
当然,这道题用正向的switch-case也可以做,不过与if-else结构差不多。
其他解法
待补充,这周出去聚餐,太累了,文章有点水,见谅。