算法——查找一个ip地址数组中,出现次数最多的ip

一道算法题

找出一组ip地址中,出现次数最多的ip,例:
输入
["192.168.12.32", "192.168.0.32", "192.168.12.32"]
输出
"192.168.12.32"

暴力破解法

function filterIp(ipArr) {
    let maxIp = '';
    let maxCount = 0;
    for(let i = 0; i < ipArr.length; i++) {
        let cur = ipArr[i];
        let sum = 0;
        for(let j = 0; j < ipArr.length; j++) {
            if(cur === ipArr[j]){
                sum++;
            }
        }
        if(sum > maxCount) {
            maxCount = sum;
            maxIp = cur;
        }
    }

    return maxIp;
}
console.time()
filterIp(arr)
console.timeEnd()
default: 0.9111328125 ms

哈希表

function filterIp(ipArr) {
    const map = {};
    for(let i = 0; i < ipArr.length; i++) {
        // 如果map中存在当前ip的key值,则表示该ip已经被统计过了。
        if(map[ipArr[i]]){
            continue;
        }

        let cur = ipArr[i];
        let sum = 0;

        // 从 i 开始,i 之前的一定是被统计过了的
        for(let j = i; j < ipArr.length; j++) {
            if(cur === ipArr[j]){
                sum++;
            }
        }
        // 写入map中
        map[cur] = sum;
    }

    let max = 0;
    let maxIp= '';
    for(let key in map){
        if(map[key] > max){
            max = map[key];
            maxIp= key;
        }
    }
    return maxIp;
}
console.time()
filterIp(arr)
console.timeEnd()
default: 0.208740234375 ms

字典树搜索

class Node {
    constructor(data){
        this.data = data;
    }

    data = '';
    count = 1;
    leaf = [];

    addLeaf(leaf) {
        this.leaf.push(leaf);
    }
    findLeaf(data) {
        for(let i = 0; i < this.leaf.length; i++) {
            if(this.leaf[i].data === data){
                return this.leaf[i];
            }
        }
        return null;
    }
    addCount(){
        this.count++;
    }
}

function createIpTree(ipArr){
    // 根节点为空
    let root = new Node('');
    for(let i = 0; i < ipArr.length; i++){
        let pointer = root;
        ipArr[i].split('.').forEach(item => {
            let includesLeaf = pointer.findLeaf(item);
            if(includesLeaf){
                includesLeaf.addCount();
                pointer = includesLeaf;
            } else {
                let node = new Node(item);
                pointer.addLeaf(node);
                pointer = node;
            }
        })
    }

    return root;
}

function depthFirstSearch(pointer) {
    let maxLeaf = pointer.leaf[0];
    for(let i = 0; i < pointer.leaf.length; i++) {
        if(pointer.leaf[i].count > maxLeaf.count){
            maxLeaf = pointer.leaf[i];
        }
    }
    return maxLeaf;
}

function filterIp(ipArr){
    // 创建字典树
    const ipTree = createIpTree(ipArr);

    // 深度优先搜索字典树,找出每个节点 count 最大的叶子,向下寻找
    let pointer = ipTree;
    let strArr = [];
    while(pointer.leaf.length) {
        let maxLeaf = depthFirstSearch(pointer);
        pointer = maxLeaf;
        strArr.push(maxLeaf.data);
    }

    return strArr.join('.');
}
console.time()
filterIp(arr)
console.timeEnd()

tree: 0.26220703125 ms

字典树居然没有哈希表快?????

哈希表我可能用的不太好,我感觉还有优化方法,不过没有深入去想了。

可能还有别的方法,不过我暂时就想到这三个了。

上一篇:docker panic invalid freelist page 5, page type is leaf的解决处理


下一篇:gcc编译背后的故事及其常用命令