Cattle customer network algorithm Summary (2)

A: tree

1. origami problem

[Title] Please note some vertically on the table, and then from below upward folded piece of paper once, press out creases after expansion. In this case the fold is concave, i.e., the direction of projection creases directed back surface of the paper. If the continuous folded in half twice, pushed out from the lower fold strip to expand upward, then there are three folds, top to bottom are the fold, the fold and crease. Given an input parameter N, from below are representative of a continuous strip folded N times, please print all directions from top to bottom fold upwardly. For example: N = 1, printing: down N = 2, printing: down down up

/**
 * 折纸问题,就是一棵左结点为down,右结点为up的二叉树
 */
public class Paper {
    static class TreeNode{
        private String val;
        private TreeNode left;
        private TreeNode right;

        public TreeNode(String val) {
            this.val = val;
        }

        @Override
        public String toString() {
            return "TreeNode{" +
                    "val=" + val +
                    ", left=" + left +
                    ", right=" + right +
                    '}';
        }
    }
    public static void print(int N){
        if (N < 1)
            return;
        TreeNode root = new TreeNode("down");
        build(root,N);
        print(root);
    }

    private static void print(TreeNode node){
        if (node.left != null)
            print(node.left);
        System.out.println(node.val);
        if (node.right != null)
            print(node.right);
    }

    private static void  build(TreeNode node,int N){
        if (N <= 1)
            return;
        node.left = new TreeNode("down");
        node.right = new TreeNode("up");
        build(node.left,N-1);
        build(node.right,N-1);
    }


    public static void main(String[] args) {
        print(3);
    }
}

2. The first binary sequence, the sequence, after the non-recursive traversal

    //递归前序遍历
    public static void pre1(TreeNode node){
        if (node == null)
            return;
        System.out.printf(node.val+" ");
        pre1(node.left);
        pre1(node.right);
    }

    //非递归前序遍历
    public static void pre2(TreeNode node){
        if (node == null)
            return;
        Stack<TreeNode> stack = new Stack<>();
        while (!stack.isEmpty() || node != null){
            //把所有左结点加入到栈
            if (node != null){
                System.out.printf(node.val+" ");
                stack.push(node);
                node = node.left;
            }
            //左结点都为空,把上一个结点的右结点入栈
            else
                node = stack.pop().right;
        }
    }

    //递归中序遍历
    public static void in1(TreeNode node){
        if (node == null)
            return;
        in1(node.left);
        System.out.printf(node.val+" ");
        in1(node.right);
    }

    //非递归中序遍历
    public static void in2(TreeNode node){
        if (node == null)
            return;
        Stack<TreeNode> stack = new Stack<>();
        while (!stack.isEmpty() || node != null){
            //把所有左结点加入到栈
            if (node != null){
                stack.push(node);
                node = node.left;
            }
            //左结点都为空,把上一个结点的右结点入栈
            else
            {
                node = stack.pop();
                System.out.printf(node.val+" ");
                node = node.right;
            }
        }
    }

    //递归后序遍历
    public static void post1(TreeNode node){
        if (node == null)
            return;
        post1(node.left);
        post1(node.right);
        System.out.printf(node.val+" ");
    }

    //非递归后序遍历
    public static void post2(TreeNode node){
        if (node == null)
            return;
        ArrayList<TreeNode> nodes = new ArrayList<>();
        Stack<TreeNode> stack = new Stack<>();
        while (!stack.isEmpty() || node != null){
            //把所有右结点加入到栈
            if (node != null){
                nodes.add(node);
                stack.push(node);
                node = node.right;
            }
            //右结点都为空,把上一个结点的左结点入栈
            else
                node = stack.pop().left;
        }
        Collections.reverse(nodes);
        for (TreeNode node1:
             nodes) {
            System.out.printf(node1.val+" ");
        }
    }

3. morris traversal

Features:

  • Time complexity is O (N), the spatial complexity is O (1), and tree traversal process does not change the shape of
  • For node has a left subtree, visited twice, for no left child node of the tree, only one visit
  • In general, the left, the current node, the right direction along the current node

Claim:

  • cur no left subtree, move to the right (no road left, then I go directly to the right)
  • cur have left subtree, find the rightmost left sub-tree node mostRight
    • mostRight right child is empty: mostRight = cur, cur move to the left (labeled themselves once, go to the left to see)
    • mostRight right child is cur: mostRight = null, cur move to the right (see their mark, and I have gone through the left side, directly to the right)
/**
 * morris遍历
 */
public class MorrisTravel {
    static class TreeNode {
        private int val;
        private TreeNode left;
        private TreeNode right;

        public TreeNode(int val) {
            this.val = val;
        }

        @Override
        public String toString() {
            return "TreeNode{" +
                    "val=" + val +
                    ", left=" + left +
                    ", right=" + right +
                    '}';
        }
    }

    public static void inTravel(TreeNode root) {
        if (root == null)
            return;
        TreeNode cur = root;
        TreeNode next = null;
        while (cur != null) {
            next = cur.left;
           //有左子树
            if (next != null) {
                while (next.right != cur && next.right != null)
                    next = next.right;
                //第一次访问,改一下指针,向左走(中断)
                if (next.right == null) {
                    next.right = cur;
                    cur = cur.left;
                    continue;
                }
                //第二次访问,修复指针,向右走↓
                else
                    next.right = null;
            }

            //左子树遍历完成(左-根-右)
            System.out.printf(cur.val + " ");
            cur = cur.right;
        }
    }

    public static void preTravel(TreeNode root) {
        if (root == null)
            return;
        TreeNode cur = root;
        TreeNode next = null;
        while (cur != null) {
            next = cur.left;
           //有左子树
            if (next != null) {
                while (next.right != cur && next.right != null)
                    next = next.right;
                //第一次访问,改一下指针,向左走(中断)
                if (next.right == null) {
                     next.right = cur;
                    //(根-左)
                    System.out.printf(cur.val + " ");
                    cur = cur.left;
                    continue;
                }
                //第二次访问,修复指针,向右走↓
                else
                    next.right = null;
            }
            //左子树遍历完成
            else
                //(根-右)
                System.out.printf(cur.val + " ");
            cur = cur.right;

        }
    }

    public static void postTravel(TreeNode root) {
        if (root == null)
            return;
        TreeNode cur = root;
        TreeNode next = null;
        while (cur != null) {
            next = cur.left;
           //有左子树
            if (next != null) {
                while (next.right != cur && next.right != null)
                    next = next.right;
                //第一次访问,改一下指针,向左走(中断)
                if (next.right == null) {
                    next.right = cur;
                    cur = cur.left;
                    continue;
                }
                //第二次访问,修复指针,向右走↓
                else
                {
                    next.right = null;
                    //已经走完左边和右边了(左-右-根)
                    //打印左子树的倒置右结点
                    reverse(cur.left);
                }
            }
            cur = cur.right;

        }
        //打印根节点的倒置右结点
        //左边和右边都走完了
        reverse(root);
    }

    private static void reverse(TreeNode node){
        if (node == null)
            return;
        TreeNode next = node.right;
        TreeNode temp = null;
        node.right = null;
        while (next != null){
            temp = next.right;
            next.right = node;
            node = next;
            next = temp;
        }
        next = node;
        while (next != null){
            System.out.printf(next.val + " ");
            next = next.right;
        }
        next = node.right;
        node.right = null;
        while (next != null){
            temp = next.right;
            next.right = node;
            node = next;
            next = temp;
        }
    }
}

4. Find the successor of a node in a binary tree

[Title] Now there is a new binary tree node types are as follows:

public class Node { 
	public int value; 
	public Node left; 
	public Node right; 
	public Node parent;
	public Node(int data) { this.value = data; }
}

This configuration more than a parent pointer pointing to a parent node than conventional binary tree node structure. Suppose a binary Node type nodes, each node in the tree parent pointers are properly directed their parent node, the first node to the parent null. Only one node to node in a binary tree, implement a function that returns the node's successor nodes. In the sequence preorder traversal of the binary tree, the next node node to node is called the successor node.

    public static Node nextNode(Node node){
        if (node == null)
            return null;
        //中序遍历是左-中-右
        //如果有右结点,那么就在下一层找,找到右孩子的最左边的结点
        if (node.right != null){
            node = node.right;
            while (node != null && node.left != null) {
                node = node.left;
            }
            return node;
        }
        //如果没有右结点,那么就只能往上一层查找,找到一个作为左结点的父结点
        else
            while (node.parent != null && node != node.parent.left)
                node = node.parent;
            return node.parent;
    }

5. What is the prefix tree? How to generate a prefix tree?

/**
 * 前缀树
 */
public class PrefixTree {
    static class PrefixNode {
        //经过结点的单词个数
        private int pass;
        //单词长度
        private int end;
        //下一个结点
        private HashMap<Integer, PrefixNode> nexts;

        public PrefixNode() {
            pass = 0;
            end = 0;
            nexts = new HashMap<>();
        }

        @Override
        public String toString() {
            return "PrefixNode{" +
                    "pass=" + pass +
                    ", end=" + end +
                    ", nexts=" + nexts +
                    '}';
        }
    }
    private PrefixNode root;

    public PrefixTree() {
        root = new PrefixNode();
    }

    public void insert(String word){
        if (word == null || word.length() == 0)
            return;
        PrefixNode node = root;
        PrefixNode next;
        for (int i = 0; i < word.length(); i++) {
            char s = word.charAt(i);
            next = node.nexts.get((int)s);
            if (next == null)
                 next = new PrefixNode();
            node.nexts.put((int)s,next);
            next.pass++;
            node = next;
        }
        node.end++;
    }

    public void remove(String word){
        if (prefixSize(word) != 0)
        {
            PrefixNode node = root;
            PrefixNode next;
            for (int i = 0; i < word.length(); i++) {
                char s = word.charAt(i);
                next = node.nexts.get((int)s);
                if (--next.pass == 0){
                    node.nexts.put((int)s,null);
                    return;
                }
                node = next;
            }
            node.end--;
        }
    }

    public int prefixSize(String prefix){
        PrefixNode node = root;
        if (prefix == null || prefix.length() == 0)
            return 0;
        int index = 0;
        while (index < prefix.length() && node != null)
        {
            char c = prefix.charAt(index++);
            node = node.nexts.get((int)c);
        }
        if (node == null)
            return 0;
        return node.pass;
    }

    public int count(String word){
        PrefixNode node = root;
        if (word == null || word.length() == 0)
            return 0;
        int index = 0;
        while (index < word.length() && node != null)
        {
            char c = word.charAt(index++);
            node = node.nexts.get((int)c);
        }
        if (node == null)
            return 0;
        return node.end;
    }

    @Override
    public String toString() {
        return "PrefixTree{" +
                "root=" + root +
                '}';
    }
}

Print array

A string type array arr1, another string array of type arr2. arr2 in which characters are arr1 appear in? Please print

arr2 in which characters are in a string prefix as arr1 occur? Please print

    public static void main(String[] args) {
        PrefixTree tree = new PrefixTree();
        String[] arr1 = {"abc","abd","bcd"};
        String[] arr2 = {"abd","cc","ab"};

        //打印数组
        for (int i = 0; i < arr1.length; i++) {
            tree.insert(arr1[i]);
        }
        System.out.println("出现的字符:");
        for (int i = 0; i < arr2.length; i++) {
            if (tree.count(arr2[i]) > 0)
                System.out.println(arr2[i]);
        }
        System.out.println("作为前缀的字符:");
        for (int i = 0; i < arr2.length; i++) {
            if (tree.prefixSize(arr2[i]) > 0)
                System.out.println(arr2[i]);
        }

    }

II: bloom filter

Role: Blacklist is a large file, used to filter certain information. If the information belongs to the blacklist, it will be filtered; if the information does not belong to the black list may also be filtered mistakes.

Structure: large arrays, array element is one bit

Location information:

  1. Positioning the array index: X / digits
  2. Digits positioning of the index: X%-digit

Black description:

  1. K ready hash functions
  2. Information respectively hash function to obtain a hash value of K, the corresponding K bits describe black

Detection:

  1. Information respectively hash function to obtain a hash value of K
  2. If the corresponding bit is black, the interception; if there is not a bit of black, then let

Features:

  • Regardless of the size of a single sample
  • The number of samples and the error rate related

Three: consistent hashing

The original structure

  1. The client sends a key, a request value
  2. The server obtains a hash value by a hash function to the key, the number of the server module, the service providing server X determines
  3. Services provided by the X server

problem:

  • Increase server and delete, data migration costs high
  • Changes to the code

Improved Structure

  1. Ip server by a hash value obtained for each server, connected to form a ring
  2. The client sends a key, a request value
  3. By the server hash function obtains a hash value of the key, hit the ring, ring X server determines the next direction clockwise (as determined by dichotomy)
  4. Services provided by the X server

Features:

  • After you add a server X1, find the next server in a clockwise direction X2, and asked him to pass the data X1-X0 X1
  • Primary server number is small, unbalanced load
  • After adding servers, load imbalance

Then improved structure

  1. Each server allocates a certain amount of virtual nodes on the routing table
  2. Server by obtaining a hash value for each node for each virtual server, connected to form a ring

Four: hash table

1. disjoint-set

  1. Find two elements belong to the same set of
  2. The two sets into one big collection
/**
 * 并查集
 */
public class UnionSet {
    static class Node{
        private int val;

        public Node(int val) {
            this.val = val;
        }
    }
    //记录每个节点的代表节点
    HashMap<Node,Node> fathers;
    //记录每个代表节点的集合个数
    HashMap<Node,Integer> sizes;

    public UnionSet(List<Node> nodes){
        fathers = new HashMap<>();
        sizes = new HashMap<>();
        build(nodes);
    }

    //初始化
    private void build(List<Node> nodes){
        fathers.clear();
        sizes.clear();
        for (Node node :
                nodes) {
            fathers.put(node, node);
            sizes.put(node,1);
        }
    }

    //查找代表节点
    private Node findPresent(Node node){
        Node present = fathers.get(node);
        //找出代表节点为本身的节点
        if (present != node) {
            present = findPresent(present);
        }
        //找到之后,把其他节点都更新代表节点,加快查询速度
        fathers.put(node,present);
        return present;
    }

    //判断是否是同一个集合
    public boolean isSame(Node a,Node b){
        if (a == null || b == null)
            return false;
        return findPresent(a) == findPresent(b);
    }

    //合并集合
    public void union(Node a,Node b){
        if (a == null || b == null || isSame(a,b))
            return;
        int size1 = sizes.get(a);
        int size2 = sizes.get(b);
        if (size1 > size2) {
            fathers.put(b, a);
            sizes.put(a,size1+size2);
        }
        else {
            fathers.put(a, b);
            sizes.put(b,size1+size2);
        }
    }
}

2. Islands issue

Only two kinds of values ​​of 0 and 1 in a matrix, and each location can be on their own, is connected to the lower, left, and right positions

If there is a 1 together, this part is called an island, Seeking a matrix of how many islands?

For example:
0 0 0. 1. 1 0
. 1. 1. 1 0 0. 1
. 1. 1 0 0 0 0
0 0 0 0 0 0
The matrix has three islands

/**
 * 岛问题
 */
public class Island {
    static int sum = 0;

	//遍历岛
    public static int getIsland(int[][] matrix){
        if (matrix == null || matrix[0] == null)
            return 0;
        int N = matrix.length;
        int M  = matrix[0].length;
        for (int i = 0; i < N; i++) {
            for (int j = 0; j < M; j++) {
                if (matrix[i][j] == 1){
                	//找到有病毒的岛,开始感染
                    sum++;
                    getIsland(matrix,i,j,N,M);
                }
            }
        }
        return sum;
    }
    //不断感染,直到没有病菌
    public static void getIsland(int[][] matrix,int x,int y,int N,int M){
        if (x < 0 || y < 0 || x >= N || y >= M || matrix[x][y] != 1)
            return;
        matrix[x][y] = 2;
        getIsland(matrix,x+1,y,N,M);
        getIsland(matrix,x-1,y,N,M);
        getIsland(matrix,x,y+1,N,M);
        getIsland(matrix,x,y-1,N,M);

    }
    public static void main(String[] args) {
        int[][] matrix = {{0,0,1,0,1,0},{1,1,1,0,1,0},{1,0,0,1,0,0},{0,0,0,0,0,0}};
        System.out.println(getIsland(matrix));
    }
}

2. always find the median of the data stream

[Title] has to spit out a steady stream of data stream integer, assuming you have enough space to hold the spit number. Please design a structure MedianHolder named, all spit median number of prior MedianHolder can be obtained at any time.

【Claim】

  1. If the number N MedianHolder discharge has been saved, then any time a new number is added to the process MedianHolder, the time complexity of O (logN).
  2. Has made a whole number N of ejection processes of the median, the time complexity is O (1)
/**
 * 保存中位数
 */
public class MedianHolder {
    class MyComparator implements Comparator<Integer> {
        @Override
        public int compare(Integer o1, Integer o2) {
            if (o1 > o2)
                return -1;
            else if(o1 < o2)
                return 1;
            else
                return 0;
        }
    }
    //最小堆和最大堆
    PriorityQueue<Integer> min = new PriorityQueue<>();
    PriorityQueue<Integer> max = new PriorityQueue<>(new MyComparator());

    //最小堆只添加比自己大的数字,这样才不用调整
    //最大堆只添加比自己小的数字,或者比自己大又比其他小的数字
    //维持两个堆的平衡
    public void add(int num){
        if (max.isEmpty() || num <= max.peek())
            max.add(num);
        else if (min.isEmpty() || num >= min.peek())
            min.add(num);
        else
            max.add(num);
        modify();
    }

    //保证两个堆最多相差一个
    private void modify(){
        if (min.size() - max.size() > 1)
            max.add(min.poll());
        if (max.size() - min.size() > 1)
            min.add(max.poll());
    }

    //奇数个数字,则在多一个数量的堆里面
    //偶数个数字,取中间值
    public int get(){
        if (max.isEmpty() && min.isEmpty())
            return Integer.MIN_VALUE;
        if (min.isEmpty())
            return max.peek();
        if (max.isEmpty())
            return min.peek();
        int minSize = min.size();
        int maxSize = max.size();
        if ((maxSize+minSize) % 2 == 0)
            return (max.peek() + min.peek())/2;
        else if (maxSize > minSize)
            return max.peek();
        else
            return min.peek();
    }
}

Guess you like

Origin blog.csdn.net/weixin_36904568/article/details/94056371