LintCode 930: Connected Components in List (link-list/map/set/union-find)

930. Connected Components in List

Given a doubly linked list and an array of nodes. If the nodes are connected with each other(which means we can access any nodes through any one of them), we can consider them as one block. Find the number of blocks in the given array.

Example

Example 1:

Input:1<->2<->3<->4,[1,3,4]
Output:2
Explanation:There is no node connected with 1, and node 3 is connected with 4. So the number of blocks is 2.

Example 2:

Input:1<->2<->3<->4,[1,2,3,4]
Output:1
Explanation:All nodes  are connected.So the number of blocks is 1.

Notice

You can assume that there is no duplicate node in the given doubly linked list.

Input test data (one parameter per line)How to understand a testcase?

解法1:
我开始的想法是枚举nodes数组,每次往前和往后遍历链表,如果发现链表节点不在node数组中就相当于发现了一个新的component。注意在遍历链表过程中,set visited flag。需要用到list_mp和node_mp两个map。
list_mp<int, node*>保存node->val和node地址的映射,
node_mp<int, bool> 保存nodes中的节点和其是否访问过的关系。所以链表中的节点可以有3种状态:
1. 在node_mp中,状态为unvisited;
3. 在node_mp中,状态为visited;
3. 不在node_mp中;

/**
  * Definition of Doubly-ListNode
 * class DoublyListNode {
 * public:
 *     int val;
 *     DoublyListNode *next, *prev;
 *     DoublyListNode(int val) {
 *         this->val = val;
 *         this->prev = this->next = NULL;
 *     }
 * }
 */

class Solution {
public:
    /**
     * @param head: the given doubly linked list
     * @param nodes: the given nodes array
     * @return: the number of blocks in the given array
     */
    int blockNumber(DoublyListNode * head, vector<int> &nodes) {
        int n = nodes.size();
        map<int, DoublyListNode*> list_mp;
        map<int, bool> node_mp; //<node_dex, visited>
        int count = 0;

        DoublyListNode * node = head;
        while(node) {
            list_mp[node->val] = node;
            node = node->next;
        }
        
        for (int i = 0; i < n; ++i) {
            node_mp[nodes[i]] = false;
        }
        
        for (int i = 0; i < n; ++i) {
            if (!node_mp[nodes[i]]) {
                count++;
                node = list_mp[nodes[i]];
                while(node && (node_mp.find(node->val) != node_mp.end()) && !node_mp[node->val]) { //if the node is in nodes and unvisited
                    node_mp[node->val] = true;
                    node = node->next;
                }
                node = list_mp[nodes[i]]->prev;
                while(node && (node_mp.find(node->val) != node_mp.end()) && !node_mp[node->val]) { //if the node is in nodes and unvisited
                    node_mp[node->val] = true;
                    node = node->prev;
                }
            }
        }
        
        return count;
    }
};

解法2:
解法1需要往前和往后遍历链表,其实我们如果从前往后遍历链表,就不需要再往前走回头路了。
解法2的nodes_mp跟解法1的nodes_mp一样,也是保存3种状态。

/**
  * Definition of Doubly-ListNode
 * class DoublyListNode {
 * public:
 *     int val;
 *     DoublyListNode *next, *prev;
 *     DoublyListNode(int val) {
 *         this->val = val;
 *         this->prev = this->next = NULL;
 *     }
 * }
 */

class Solution {
public:
    /**
     * @param head: the given doubly linked list
     * @param nodes: the given nodes array
     * @return: the number of blocks in the given array
     */
    int blockNumber(DoublyListNode * head, vector<int> &nodes) {
        int n = nodes.size();
        unordered_map<int, bool> nodes_mp; //<node_val, visited>
        int count = 0;

        for (int i = 0; i < n; ++i) {
            nodes_mp[nodes[i]] = false;
        }
        
        DoublyListNode * node = head;
        while(node) {
            if (nodes_mp.find(node->val) != nodes_mp.end() && !nodes_mp[node->val]) {
                count++;
                while (node && nodes_mp.find(node->val) != nodes_mp.end() && !nodes_mp[node->val]) {
                    nodes_mp[node->val] = true;
                    node = node->next;
                }
            } else {
                node = node->next;
            }
        }

        return count;
    }
};

解法3:
我们其实不需要visited状态。因为我们是从前往后单向遍历链表,不会走回头路。所以用set即可。

/**
  * Definition of Doubly-ListNode
 * class DoublyListNode {
 * public:
 *     int val;
 *     DoublyListNode *next, *prev;
 *     DoublyListNode(int val) {
 *         this->val = val;
 *         this->prev = this->next = NULL;
 *     }
 * }
 */

class Solution {
public:
    /**
     * @param head: the given doubly linked list
     * @param nodes: the given nodes array
     * @return: the number of blocks in the given array
     */
    int blockNumber(DoublyListNode * head, vector<int> &nodes) {
        int n = nodes.size();
        unordered_set<int> node_set;
        int count = 0;

        for (int i = 0; i < n; ++i) {
            node_set.insert(nodes[i]);
        }
        
        DoublyListNode * node = head;
        while(node) {
            if (node_set.find(node->val) != node_set.end()) {
                count++;
                while (node && node_set.find(node->val) != node_set.end()) {
                    node_set.insert(node->val);
                    node = node->next;
                }
            } else {
                node = node->next;
            }
        }

        return count;
    }
};

解法4:union-find,find用非递归路径压缩算法。
注意:
1) 通常father[]可以用数组表示,但这里因为我们要考虑链表的元素个数,而不是nodes[]的数组个数。而我们又不知道链表有多少个,所以最好用map,要不就要搞一个很大的数组了。
2)算count的时候,可以先把count设为nodes.size(),每次merge减一。
也可以不这么做,在最后遍历father,看father.first==father.second,即father(a)==a,就相当于发现了一个并查集的顶点,然后res+1即可。

/**
  * Definition of Doubly-ListNode
 * class DoublyListNode {
 * public:
 *     int val;
 *     DoublyListNode *next, *prev;
 *     DoublyListNode(int val) {
 *         this->val = val;
 *         this->prev = this->next = NULL;
 *     }
 * }
 */

class Solution {
public:
    /**
     * @param head: the given doubly linked list
     * @param nodes: the given nodes array
     * @return: the number of blocks in the given array
     */
      
    // with the path compression
    int find(int a){
        int x = a;
        while (father[x] != x){
            x = father[x];
        }
        
        int nx;
        int y = a;
        while (father[y] != y){
            nx = father[y];
            father[y] = x;
            y = nx;
        }
        return x;
    }
    
    void connect(int a, int b){
        int fa = find(a);
        int fb = find(b);

        if (fa != fb){
            father[fa] = fb;
            count--;
        }
    }
    
    int blockNumber(DoublyListNode * head, vector<int> &nodes) {
        int n = nodes.size();
        unordered_set<int> node_set;
        count = n;
        for (int i = 0; i < n; ++i) {
            father[nodes[i]] = nodes[i];
            node_set.insert(nodes[i]);
        }
        DoublyListNode *node = head;
        while(node != NULL && node->next != NULL){
            if (node_set.find(node->val) != node_set.end() && 
                node_set.find(node->next->val) != node_set.end()) {
                connect(node->next->val, node->val);
            }
            node = node->next;
        }
        //int res = 0;
        //for (auto f: father){
        //    if ((f.first == f.second) && (node_set.find(f.first) != node_set.end()))
        //        res++;
        //}
        //return res;
        return count;
        
    }
private:
    int count = 0;
    map<int, int> father;
};

union-find的另一个版本,find用递归版路径压缩算法。
 

/**
  * Definition of Doubly-ListNode
 * class DoublyListNode {
 * public:
 *     int val;
 *     DoublyListNode *next, *prev;
 *     DoublyListNode(int val) {
 *         this->val = val;
 *         this->prev = this->next = NULL;
 *     }
 * }
 */

class Solution {
public:
    /**
     * @param head: the given doubly linked list
     * @param nodes: the given nodes array
     * @return: the number of blocks in the given array
     */
      
    // with the path compression
    int find(int a){
        if (father[a] == a) return a;
        else {
            father[a] = find(father[a]);
        }
    }
    
    void connect(int a, int b){
        int fa = find(a);
        int fb = find(b);

        if (fa != fb){
            father[fa] = fb;
            count--;
        }
    }
    
    int blockNumber(DoublyListNode * head, vector<int> &nodes) {
        int n = nodes.size();
        unordered_set<int> node_set;
        count = n;
        for (int i = 0; i < n; ++i) {
            father[nodes[i]] = nodes[i];
            node_set.insert(nodes[i]);
        }
        DoublyListNode *node = head;
        while(node != NULL && node->next != NULL){
            if (node_set.find(node->val) != node_set.end() && 
                node_set.find(node->next->val) != node_set.end()) {
                connect(node->next->val, node->val);
            }
            node = node->next;
        }
 
        return count;
        
    }
private:
    int count = 0;
    map<int, int> father;
};


 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值