先上题目
在柠檬水摊上,每一杯柠檬水的售价为 5
美元。
顾客排队购买你的产品,(按账单 bills
支付的顺序)一次购买一杯。
每位顾客只买一杯柠檬水,然后向你付 5
美元、10
美元或 20
美元。你必须给每个顾客正确找零,也就是说净交易是每位顾客向你支付 5
美元。
注意,一开始你手头没有任何零钱。
如果你能给每位顾客正确找零,返回 true
,否则返回 false
。
示例:
思路:题目很长,希望大家能耐心看完。题意类型是给定一个数组,判断能不能走到数组最后。首先我们至少需要遍历一次数组,在数组遍历的过程,对零钱“张数”进行计数,在通过张数来判断是否能完成找零。“5”不用找零直接收下,“10”手中至少有一张“5”,"20"手中至少有一张“10”和一张“5”或者至少3张“5”(这里需要考虑优先级,就像在日常生活中,我们找钱的过程会给面值大的钱。否则后面就没有“5”,就无法对“10”找零)
代码一:(耗时8ms if-else if-else)
bool lemonadeChange(int* bills, int billsSize) {
int fiveChange=0,tenChange=0,i=0;
while(i<billsSize){
if(bills[i]==5){
fiveChange++;
}else if(bills[i]==10){
if(fiveChange>=1){
fiveChange--;
tenChange++;
}else{
return false;
}
}else{
if(fiveChange>=1&&tenChange>=1){
fiveChange--;
tenChange--;
}else if(fiveChange>=3){
fiveChange-=3;
}else{
return false;
}
}
i++;
}
return true;
}
代码二:(耗时4ms switch case)
bool lemonadeChange(int* bills, int billsSize) {
int fiveChange=0,tenChange=0,i=0;
while(i<billsSize){
switch(bills[i]){
case 5:
fiveChange++;
break;
case 10:
if(fiveChange>=1){
fiveChange--;
tenChange++;
}else{
return false;
}
break;
case 20:
if(fiveChange>=1&&tenChange>=1){
fiveChange--;
tenChange--;
}else if(fiveChange>=3){
fiveChange-=3;
}else{
return false;
}
break;
default:
break;
}
i++;
}
return true;
}
给了两种做法:都是平时习惯的做法。在这里有个算法效率的注意点:
if 语句每一句都是独立的,例如:
if (i== 0) ...
else if (i == 1) ...
这样 i 要被读入寄存器两次,0 和 1 分别被读入寄存器一次。于是我们会发现其实 i 读两次是有点多余的,在全部比较完之前只需要一次读入寄存器就行了,其余都是额外开销。但是if 语句必须每次都把里面的两个数从内存拿出来读到寄存器,因为它不知道你其实比较的是同一个i。于是 switch case 就出来了,把上面的改成 switch case 版本:
switch (i) {
case 0:
break;
case 1:
}
因为当虚拟机读到switch的时候将所有的判断数据都加载在内存中了,而if是边判断边加载,所以就慢一些,
一般如果判断数据不多,而且是byte,short,int或是char类型的时候一般用switch,那样效率比较高.
扩展:假设我要最后要进行算账?那应该如何做?
我们可以加上一个twentyChange进行计数,最后通过张数进行“+5”“+10”“+20”。面额增加同理