929. 独特的电子邮件地址【简单题】【每日一题】
思路:【哈希模拟】
遍历emails
数组,对每个邮箱email
按 @
进行切分,左侧为local
,右侧为domain
,对local
进行进一步处理。
如果local
包含+
,则将自+
往右的字符全部截掉;然后从左到右遍历新的local
,将.
去掉,最后将local
与domain
拼接起来尝试存入哈希集合set
中,如果添加成功,则计数变量cnt
自增1
。
当所有的邮箱处理完之后,返回cnt
即可。
代码:
class Solution {
public int numUniqueEmails(String[] emails) {
int cnt = 0;
Set<String> set = new HashSet<>();
for (String email : emails) {
int split = email.indexOf('@');
String domain = email.substring(split);
String local = email.substring(0,split);
if (local.contains("+")){
int idx = local.indexOf('+');
local = local.substring(0,idx);
}
StringBuilder sb = new StringBuilder();
for (char c : local.toCharArray()) {
if (c != '.'){
sb.append(c);
}
}
local = sb.toString();
if (set.add(local+domain)){
cnt++;
}
}
return cnt;
}
}
剑指 Offer II 073. 狒狒吃香蕉【中等题】
思路:【二分查找】
我们模拟一遍这个狒狒吃香蕉的过程,设速度为k
。
遍历这n
堆香蕉,
如果香蕉堆里的香蕉小于等于k
,那么吃掉这堆香蕉需要用1
小时,我们假设距警卫回来还有remain
小时(remain
初始值为警卫的离开时间h
),那么remain--
;
如果香蕉堆里的香蕉大于k
,那么吃掉这堆香蕉消耗的时间为i/k
,结果向上取整,将花费的时间在remain
中减掉。
遍历完之后判断remain
与0
的大小关系,
如果remain>0
,说明香蕉吃完了,警卫还没回来;
如果remain==0
,说明刚好香蕉吃完,警卫回来;
如果remain<0
,说明香蕉还没吃完,警卫就回来了。
我们可以通过二分查找的方式来求出使remain==0
的k
的最小值。
根据题意,狒狒吃香蕉的速度k
最小取1
,最大取香蕉堆中的最大值(因为警卫离开的时间至少为n
)
于是,令left = 1,right = max
(max
为香蕉堆的最大值)。
当left<=right
时,进入while
循环,令k
为left
和right
的中间值,对当前的k
值进行上述狒狒吃香蕉的模拟。
当remain >= 0
时,说明k
值大了,香蕉吃完了,警卫还没回来,此时考虑缩小k
,更新右区间;
当remain < 0
时,说明k
值小了,香蕉还没吃完,警卫就回来了,此时考虑扩大k
,更新左区间。
当二分查找结束时,left
值即为我们要找的满足remain == 0 的
最小值。
代码:
class Solution {
public int minEatingSpeed(int[] piles, int h) {
int right = 0;
for (int pile : piles) {
if (pile > right){
right = pile;
}
}
int left = 1;
int remain = h;
while (left <= right){
int k = left + ((right-left)>>1);
for (int i : piles) {
if (i <= k){
remain--;
}else {
remain -= i / k;
if (i % k != 0){
remain--;
}
}
}
//remain >= 0 说明 k 值大了 香蕉吃完了 警卫还没回来
if (remain >= 0){
//更新右区间
right = k - 1;
}else {//remain < 0 说明 k 值小了 香蕉还没吃完 警卫就回来了
//更新左区间
left = k + 1;
}
//remain重置为 h 用新的k值重新模拟
remain = h;
}
return left;
}
}