一个网站域名,如"discuss.leetcode.com",包含了多个子域名。做为顶级域名,经常使用的有"com",下一级则有"leetcode.com",最低的一级为"discuss.leetcode.com"。当咱们访问域名"discuss.leetcode.com"时,也同时访问了其父域名"leetcode.com"以及顶级域名 "com"。 给定一个带访问次数和域名的组合,要求分别计算每一个域名被访问的次数。其格式为访问次数+空格+地址,例如:"9001 discuss.leetcode.com"。java
["9001 discuss.leetcode.com"]算法
["9001 discuss.leetcode.com", "9001 leetcode.com", "9001 com"]数组
例子中仅包含一个网站域名:"discuss.leetcode.com"。按照前文假设,子域名"leetcode.com"和"com"都会被访问,因此它们都被访问了9001次。app
这道题目相对来讲仍是比较简单的,看到这种String
、这种格式,平头哥首先想到的是String
的substring()
、split()
两个方法将string
转成数组或者新的字符串,事实证实平头哥的想法还阔以,竟然居于这两个方法实现了子域名访问统计,真是瞎猫碰上死耗子。可是平头哥是一名具备专研精神的非专业搬砖员,通过平头哥不严格的测试得出,subString()
方法比split()
方法效率高出一大截。这种不知道有多少层的东西用递归或者循环总归是不会错的,为何这么说呢?由于以平头哥的智商也想不出其余方式啦。平头哥基于递归或者循环实现了三种解决方式,那平头哥就来给小伙伴们介绍介绍这三种方式。dom
/** * for +while 方法 * @param cpdomains * @return */
public static List<String> whileSolution(String[] cpdomains){
// 用来存返回结果
List<String> list = new ArrayList<String>();
// 用来计数统计
Map<String, Integer> map = new HashMap<>();
for (String cpdomain : cpdomains) {
// // 先截取访问数和域名
// String[] temp = cpdomain.split(" ");
// // 访问数
// int viewCount = Integer.valueOf(temp[0]);
// // 域名
// String domain = temp[1];
int indexOf = cpdomain.indexOf(" ");
// 访问数
int viewCount = Integer.valueOf(cpdomain.substring(0, indexOf));
// 域名
String domain = cpdomain.substring(indexOf + 1);
while (domain.indexOf(".") !=-1){
mapPutOrAdd(map,domain,viewCount);
domain = domain.substring(domain.indexOf(".")+1);
}
// 最后一个顶级域名
mapPutOrAdd(map,domain,viewCount);
}
for (String key :map.keySet())
list.add(map.get(key)+" "+key);
return list;
}
复制代码
利用 while
循环来判断域名中是否包含.
,若是包含.
,则说明只要有一个子域名,由于indexOf()
方法是从左往右查找的,只要找到就返回.
所在字符串的位置,没有找到就返回-1
。若是找到了,就利用substring()
方法从返回位置的后一位开始截取到字符串的最后一位,做为新的字符串,继续走上面的流程,知道循环结束。学习
/** * 三层for 循环 * @param cpdomains * @return */
public static List<String> forSolution(String[] cpdomains) {
List<String> list = new ArrayList<String>();
Map<String, Integer> map = new HashMap<>();
// 遍历数组
for (String cpdomain : cpdomains) {
// // 先截取访问数和域名
// String[] temp = cpdomain.split(" ");
// // 访问数
// int viewCount = Integer.valueOf(temp[0]);
// // 域名
// String domain = temp[1];
int indexOf = cpdomain.indexOf(" ");
// 访问数
int viewCount = Integer.valueOf(cpdomain.substring(0, indexOf));
// 域名
String domain = cpdomain.substring(indexOf + 1);
String[] domains = domain.split("\\.");
if (domains.length == 0) continue;
// 拼接出多级域名,都塞入map
for (int i = 0; i < domains.length; i++) {
StringBuilder key = new StringBuilder(domains[i]);
for (int j = i + 1; j < domains.length; j++) {
key.append('.');
key.append(domains[j]);
}
mapPutOrAdd(map,key.toString(), viewCount);
}
}
for (String key :map.keySet())
list.add(map.get(key)+" "+key);
return list;
}
复制代码
for
循环的实现是平头哥带来的三种实现中,效率最低的。因此小伙伴们能不用双层for
就坚定不用。for
循环最要利用split()
方法将域名分离出现,例如discuss.leetcode.com
分红discuss
、leetcode
、com
。而后双层遍历将域名组合起来,最外层第一次遍历完以后获得discuss.leetcode.com
,第二次遍历完以后获得leetcode.com
,第三次遍历完以后获得com
。这样最后也获得了每一个域名的访问次数。测试
public static List<String> recurveSolution(String[] cpdomains){
List<String> list = new ArrayList<String>();
Map<String, Integer> map = new HashMap<>();
// 遍历数组
for (String cpdomain : cpdomains) {
// 先截取访问数和域名
String[] temp = cpdomain.split(" ");
// 访问数
int viewCount = Integer.valueOf(temp[0]);
// 域名
String domain = temp[1];
// 递归方法
recurve(map,domain,viewCount);
}
for (String key :map.keySet())
list.add(map.get(key)+" "+key);
return list;
}
/** * 递归方法 * @param map map集合 * @param domain 网站域名 * @param viewCount 访问数 * @return */
public static Map<String,Integer> recurve(Map<String,Integer> map,String domain,Integer viewCount){
if (domain.indexOf(".") != -1){
mapPutOrAdd(map,domain,viewCount);
return recurve(map, domain.substring(domain.indexOf(".")+1),viewCount);
}else {
mapPutOrAdd(map,domain,viewCount);
return map;
}
}
private static void mapPutOrAdd(Map<String,Integer> map, String key, Integer val) {
if (map.containsKey(key)) {
map.put(key,map.get(key) + val);
} else {
map.put(key,val);
}
}
复制代码
递归方法跟while
方式差很少,效率也不相上下。由于咱们不知道域名有多少层,用递归来作是很是合适的,由于递归就是为这个而生。每次递归的时候咱们现将域名添加到map
中,跟while
同样咱们也用indexOf(".")
来判断域名中是否含有子域名,若是存在,则截取新的域名继续调用自身,直到没有子域名为止。网站
以上就是平头哥给小伙伴们带来关于子域名访问计数的算法分享,不知道是否给小伙伴们讲明白?对于这道算法题,小伙伴们你是否还有其余思路呢?请在留言区与其余的小伙伴分享吧。ui