And check the design and LeetCode title: the number of islands

Preface

The structure of union search is most suitable for solving problems about connectivity. The following introduces the idea of ​​union search and attaches a LeetCode topic

And check the design

Let's talk about the structure and ideas first.

structure

It has three structures, one is an element map, one is a son-father map, one is a rankMap, the first map is used to package the element corresponding to the value, and the second map corresponds to the father element corresponding to each element. The third map is used to hold the size of the collection corresponding to each parent element. Let's take a look at the code

public static class Element<V>{
    
    
    V value;
    public Element(V value){
    
    
        this.value = value;
    }
}
public static class UnionAndSet<V>{
    
    
    private HashMap<Element<V>,Element<V>> fatherMap;
    private HashMap<V,Element<V>> elementMap;
    private HashMap<Element<V>,Integer> sizeMap;
    public UnionAndSet(List<V> list){
    
    
        this.fatherMap = new HashMap<>();
        this.elementMap = new HashMap<>();
        this.sizeMap = new HashMap<>();
        //初始化集合,每个元素都是一个集合
        for (V v : list) {
    
    
            Element<V> element = new Element<>(v);
            elementMap.put(v,element);
            fatherMap.put(element,element);
            sizeMap.put(element,1);
        }
    }
}

achieve

Then look at its two most important methods, union(v1,v2) and isSameSet(v1,v2);:
union的思想就是Find out the head nodes corresponding to the two elements. If the head nodes corresponding to the two elements are not Same, next we need to connect their two sets, update fatherMap and sizeMap
isSameSet:, the idea and implementation are very simple, only need to find the head nodes of the two elements, and judge whether the two head nodes are equal. , It returns true if it is equal, otherwise it returns false;
let’s take a look at the overall code:

public static class Element<V>{
    
    
    V value;
    public Element(V value){
    
    
        this.value = value;
    }
}
public static class UnionAndSet<V>{
    
    
    private HashMap<Element<V>,Element<V>> fatherMap;
    private HashMap<V,Element<V>> elementMap;
    private HashMap<Element<V>,Integer> sizeMap;
    public UnionAndSet(List<V> list){
    
    
        this.fatherMap = new HashMap<>();
        this.elementMap = new HashMap<>();
        this.sizeMap = new HashMap<>();
        //初始化集合,每个元素都是一个集合
        for (V v : list) {
    
    
            Element<V> element = new Element<>(v);
            elementMap.put(v,element);
            fatherMap.put(element,element);
            sizeMap.put(element,1);
        }
    }
    //得到两个元素所属集合的头结点
    private Element<V> getHeader(Element<V> element){
    
    
        Stack<Element<V>> stack = new Stack<>();
        Element<V> father = fatherMap.get(element);
        while(element != father){
    
    
            stack.push(element);//沿途所有节点入栈
            element = father;
            father = fatherMap.get(element);
        }
        //退出循环表示找到头结点了,这时候需要做的事情是将沿途所有节点都指向这个父节点
        while(!stack.isEmpty()){
    
    
            fatherMap.put(stack.pop(),father);
        }
        return father;
    }
    //合并两个节点
    public void union(V v1,V v2){
    
    
        //合并的前提需要两个元素都存在elementMap里
        if (elementMap.containsKey(v1) && elementMap.containsKey(v2)){
    
    
            Element<V> father_v1 = getHeader(elementMap.get(v1));
            Element<V> father_v2 = getHeader(elementMap.get(v2));
            if (father_v1 == father_v2){
    
    
                return ;
            }
            //只有在头节点不同的情况下才进行连通
            Element<V> big = father_v1;
            Element<V> small = father_v2;
            int size_v1 = sizeMap.get(big);
            int size_v2 = sizeMap.get(small);
            big = size_v1 < size_v2 ? small : big;
            small = big==father_v1?father_v2:father_v1;
            int size = sizeMap.get(big)+sizeMap.get(small);
            fatherMap.put(small,big);
            sizeMap.put(big,size);
        }
    }
    public boolean isSameSet(V v1,V v2){
    
    
        if (elementMap.containsKey(v1) && elementMap.containsKey(v2)){
    
    
            Element<V> header_v1 = getHeader(elementMap.get(v1));
            Element<V> header_v2 = getHeader(elementMap.get(v2));
            return header_v1 == header_v2;
        }
        return false;
    }
}

public static void main(String[] args) {
    
    
    List<Integer> list = new ArrayList<>();
    list.add(1);
    list.add(2);
    list.add(3);
    list.add(4);
    UnionAndSet<Integer> unionAndSet = new UnionAndSet<>(list);
    unionAndSet.union(1,2);
    unionAndSet.union(3,4);
    System.out.println(unionAndSet.isSameSet(1,3));
    unionAndSet.union(2,3);
    System.out.println(unionAndSet.isSameSet(1,3));
}

Test Results:
Insert picture description here

Practice questions

Portal

topic

Given a two-dimensional grid composed of '1' (land) and '0' (water), please count the number of islands in the grid.
Islands are always surrounded by water, and each island can only be formed by connecting adjacent land in the horizontal or vertical direction.
In addition, you can assume that all four sides of the grid are surrounded by water.

Example

Example 1:

Input:
[
['1','1','1','1','0'],
['1','1','0','1','0'],
['1 ','1','0','0','0'],
['0','0','0','0','0']
]
output: 1
example 2:

Input:
[
['1','1','0','0','0'],
['1','1','0','0','0'],
['0 ','0','1','0','0'],
['0','0','0','1','1']
]
Output: 3
Explanation: Only for each island It can be formed by connecting adjacent land in the horizontal and/or vertical direction.

thought

Its idea is the same as the idea of ​​union search set, I will not explain it in detail, but just say a few words on how to connect: we traverse this two-dimensional array, and then encapsulate each position into a value of i_j to encapsulate it into Each element, then in the process of traversal, find the position 1 and connect. I won’t say much about the rest, just look at the code

achieve

class Solution {
    
    
    public static class Element<V>{
    
    
        public V value;
        public Element(V v){
    
    
            value = v;
        }
    }
    public static class UnionAndSet<V>{
    
    
        public HashMap<V,Element<V>> elementMap;
        public HashMap<Element<V>,Element<V>> fatherMap;
        public HashMap<Element<V>,Integer> sizeMap;

        public UnionAndSet(List<V> list){
    
    
            elementMap = new HashMap<>();
            fatherMap = new HashMap<>();
            sizeMap = new HashMap<>();
            for(V v: list){
    
    
                Element<V> element = new Element<V>(v);
                elementMap.put(v,element);
                fatherMap.put(element,element);
                sizeMap.put(element,1);
            }
        }
        public Element<V> getHeader(V v){
    
    
            Element<V> element = elementMap.get(v);
            Stack<Element> stack = new Stack<>();
            while(element != fatherMap.get(element)){
    
    
                Element father = fatherMap.get(element);
                stack.push(element);
                element = father;
            }
            while(!stack.isEmpty()){
    
    
                fatherMap.put(stack.pop(),element);
            }
            return element;
        }
        public void union(V v1,V v2){
    
    
            if(elementMap.containsKey(v1) && elementMap.containsKey(v2)){
    
    
                Element father_v1 = getHeader(v1);
                Element father_v2 = getHeader(v2);
                if(father_v1 != father_v2){
    
    
                    int v1_len = sizeMap.get(father_v1);
                    int v2_len = sizeMap.get(father_v2);
                    Element<V> big = v1_len>v2_len?father_v1:father_v2;
                    Element<V> small = big==father_v1?father_v2:father_v1;
                    fatherMap.put(small,big);
                    sizeMap.put(big,v1_len+v2_len);
                    sizeMap.remove(small);
                }
            }
        }
    }
    public int numIslands(char[][] grid) {
    
    
        if(grid == null || grid.length==0 || grid[0].length==0){
    
    
            return 0;
        }
        List<String> list = new ArrayList<>();
        for(int i=0;i<grid.length;i++){
    
    
            for(int j=0;j<grid[i].length;j++){
    
    
                if(grid[i][j]=='1'){
    
    
                    String position = String.valueOf(i)+"_"+String.valueOf(j);
                    list.add(position);
                }
            }
        }
        UnionAndSet<String> unionAndSet = new UnionAndSet<>(list);
        for(int i=0;i<grid.length;i++){
    
    
            for(int j=0;j<grid[i].length;j++){
    
    
                if(grid[i][j]!='1'){
    
    
                    continue;
                }
                String position = String.valueOf(i)+"_"+String.valueOf(j);
                if(j-1>=0 && grid[i][j-1]=='1'){
    
    
                    String up = String.valueOf(i)+"_"+String.valueOf(j-1);
                    unionAndSet.union(up,position);
                }
                if(i-1>=0 && grid[i-1][j]=='1'){
    
    
                    String left = String.valueOf(i-1)+"_"+String.valueOf(j);
                    unionAndSet.union(left,position);
                }
            }
        }
        return unionAndSet.sizeMap.size();
    }
}

Guess you like

Origin blog.csdn.net/MarkusZhang/article/details/108014420