总是嫌弃CSDN发文审核要那么久,我们从算法角度分析一下

这是我最近发文时候,发现审核总是有点慢的,引起的思考。下面内容仅代表个人想法,如果冒犯,CSDN不能打我哈

  • 你有没有感受过,文章写好时候,看到待审核的焦虑。频繁的刷新,想要早点给可爱的人看看。可是怎么刷都不动,难受至极!
  • 你有没有发现过,当你修改已经发好文章时,它的审核速度又突然加快了。神奇哎!
  • 满心欢喜的点开文章,想象着自己有着破万的浏览量,多么美妙的白日梦。

在这里插入图片描述
现在我们来认真思考下,为啥CSDN它审核这么慢?
你发可能是涉及羞羞的文字,你是坏孩子。
你发可能文字超过了10万字,文章太长了。我发出了疑问,你能不能看完这么多字。
更有可能你半夜发了一篇文章,人家工作人员不上班,打烊了。等次日早晨吧。

那它是怎么审核呢,要是人工一个字一个字审核,恐怕,是大哥也要疯了!我觉得吧,在弘扬社会主义核心价值观的前提下,它要刷选哪些是值的发的,要是你坏孩子,那可不好的。比如,数据分析看看,你文章有多少不雅文字,图片是否合格,你转发的链接是否有诱导因素等等。敲黑板了,主要看中你是好孩子!
在这里插入图片描述

我们言归正传,开始我们的算法思考。

既然你写的文字就相当于在插入字符,那么是不是就相当于在一个很大容量空间里面插入一个数组,这个数组依次排开,然后组成你的文章,那么它的插入算法就是关键所在了。插入结束,我们是不是还要检索相关【不当】字符,这又是不是一个算法。
设想,我们假如我们使用链表插入,那是不是很长很长一条直线了,到时候查询时候,所有空间都遍历一遍,这个时间消耗是不是很大。要是我们使用二叉树来左右插入,是不是就保持两边都有子树,那么在查询的时候是不是只要看该字符值的大小,来确定在那个半边,最起码节省一半时间。对吧!
下面我们实现下代码
链表插入并查询

public interface Map<K, V> {

    void add(K key, V value);
    boolean contains(K key);
    V get(K key);
    void set(K key, V newValue);
    V remove(K key);
    int getSize();
    boolean isEmpty();
}

下面对创建LinkedListMap,实现对【重点字符】的查询
我这里使用的《傲慢与偏见》英文版书籍,里面有十二万字
我们查找出现 pride 和 prejudice 的频次作为我们的关键字

public class LinkedListMap<K, V> implements Map<K, V> {

    private class Node{
        public K key;
        public V value;
        public Node next;

        public Node(K key, V value, Node next){
            this.key = key;
            this.value = value;
            this.next = next;
        }

        public Node(K key){
            this(key, null, null);
        }

        public Node(){
            this(null, null, null);
        }
        @Override
        public String toString(){
            return key.toString() + " : " + value.toString();
        }
    }
    private Node dummyHead;
    private int size;
    public LinkedListMap(){
        dummyHead = new Node();
        size = 0;
    }
    @Override
    public int getSize(){
        return size;
    }
    @Override
    public boolean isEmpty(){
        return size == 0;
    }
    private Node getNode(K key){
        Node cur = dummyHead.next;
        while(cur != null){
            if(cur.key.equals(key))
                return cur;
            cur = cur.next;
        }
        return null;
    }

    @Override
    public boolean contains(K key){
        return getNode(key) != null;
    }
    @Override
    public V get(K key){
        Node node = getNode(key);
        return node == null ? null : node.value;
    }
   @Override
    public void add(K key, V value){
        Node node = getNode(key);
        if(node == null){
            dummyHead.next = new Node(key, value, dummyHead.next);
            size ++;
        }
        else
            node.value = value;
    }

    @Override
    public void set(K key, V newValue){
        Node node = getNode(key);
        if(node == null)
            throw new IllegalArgumentException(key + " doesn't exist!");

        node.value = newValue;
    }
    @Override
    public V remove(K key){
        Node prev = dummyHead;
        while(prev.next != null){
            if(prev.next.key.equals(key))
                break;
            prev = prev.next;
        }
        if(prev.next != null){
            Node delNode = prev.next;
            prev.next = delNode.next;
            delNode.next = null;
            size --;
            return delNode.value;
        }
        return null;
    }

    public static void main(String[] args){
        System.out.println("Pride and Prejudice");

        ArrayList<String> words = new ArrayList<>();
        if(FileOperation.readFile("pride-and-prejudice.txt", words)){
            System.out.println("Total words: " + words.size());

            LinkedListMap<String, Integer> map = new LinkedListMap<>();
            for(String word: words) {
                if (map.contains(word))
                    map.set(word, map.get(word) + 1);
                else
                    map.add(word, 1);
            }
            System.out.println("Total different words: " + map.getSize());
            System.out.println("Frequency of PRIDE: " + map.get("pride"));
            System.out.println("Frequency of PREJUDICE: " + map.get("prejudice"));
        }
    }
}
输出结果
Pride and Prejudice
Total words: 125901
Total different words: 6530
Frequency of PRIDE: 53
Frequency of PREJUDICE: 11

ok很完美,确实可以
我们再看看BSTMap

public class BSTMap<K extends Comparable<K>, V> implements Map<K, V> {

    private class Node{
        public K key;
        public V value;
        public Node left, right;

        public Node(K key, V value){
            this.key = key;
            this.value = value;
            left = null;
            right = null;
        }
    }

    private Node root;
    private int size;

    public BSTMap(){
        root = null;
        size = 0;
    }

    @Override
    public int getSize(){
        return size;
    }

    @Override
    public boolean isEmpty(){
        return size == 0;
    }

    // 向二分搜索树中添加新的元素(key, value)
    @Override
    public void add(K key, V value){
        root = add(root, key, value);
    }

    // 向以node为根的二分搜索树中插入元素(key, value),递归算法
    // 返回插入新节点后二分搜索树的根
    private Node add(Node node, K key, V value){

        if(node == null){
            size ++;
            return new Node(key, value);
        }

        if(key.compareTo(node.key) < 0)
            node.left = add(node.left, key, value);
        else if(key.compareTo(node.key) > 0)
            node.right = add(node.right, key, value);
        else // key.compareTo(node.key) == 0
            node.value = value;

        return node;
    }

    // 返回以node为根节点的二分搜索树中,key所在的节点
    private Node getNode(Node node, K key){

        if(node == null)
            return null;
        if(key.compareTo(node.key) == 0)
            return node;
        else if(key.compareTo(node.key) < 0)
            return getNode(node.left, key);
        else // if(key.compareTo(node.key) > 0
            return getNode(node.right, key);
    }

    @Override
    public boolean contains(K key){
        return getNode(root, key) != null;
    }

    @Override
    public V get(K key){
        Node node = getNode(root, key);
        return node == null ? null : node.value;
    }

    @Override
    public void set(K key, V newValue){

        Node node = getNode(root, key);
        if(node == null)
            throw new IllegalArgumentException(key + " doesn't exist!");

        node.value = newValue;
    }

    // 返回以node为根的二分搜索树的最小值所在的节点
    private Node minimum(Node node){
        if(node.left == null)
            return node;
        return minimum(node.left);
    }
  }

    public static void main(String[] args){

        System.out.println("Pride and Prejudice");

        ArrayList<String> words = new ArrayList<>();
        if(FileOperation.readFile("pride-and-prejudice.txt", words)){
            System.out.println("Total words: " + words.size());

            BSTMap<String, Integer> map = new BSTMap<>();
            for(String word: words) {
                if (map.contains(word))
                    map.set(word, map.get(word) + 1);
                else
                    map.add(word, 1);
            }

            System.out.println("Total different words: " + map.getSize());
            System.out.println("Frequency of PRIDE: " + map.get("pride"));
            System.out.println("Frequency of PREJUDICE: " + map.get("prejudice"));
        }
    }
}
Pride and Prejudice
Total words: 125901
Total different words: 6530
Frequency of PRIDE: 53
Frequency of PREJUDICE: 11

对比链表的,两个结果一样,达到预期效果
我们现在看下时间消耗

public class TestMapMain {

    private static double testMap(Map<String, Integer> map, String filename){

        long startTime = System.nanoTime();

        System.out.println(filename);
        ArrayList<String> words = new ArrayList<>();
        if(FileOperation.readFile(filename, words)) {
            System.out.println("Total words: " + words.size());

            for (String word : words){
                if(map.contains(word))
                    map.set(word, map.get(word) + 1);
                else
                    map.add(word, 1);
            }

            System.out.println("Total different words: " + map.getSize());
            System.out.println("Frequency of PRIDE: " + map.get("pride"));
            System.out.println("Frequency of PREJUDICE: " + map.get("prejudice"));
        }

        long endTime = System.nanoTime();

        return (endTime - startTime) / 1000000000.0;
    }

    public static void main(String[] args) {

        String filename = "pride-and-prejudice.txt";

        BSTMap<String, Integer> bstMap = new BSTMap<>();
        double time1 = testMap(bstMap, filename);
        System.out.println("BST Map: " + time1 + " s");
        System.out.println();

        LinkedListMap<String, Integer> linkedListMap = new LinkedListMap<>();
        double time2 = testMap(linkedListMap, filename);
        System.out.println("Linked List Map: " + time2 + " s");
        System.out.println();
    }
}
输出结果
pride-and-prejudice.txt
Total words: 125901
Total different words: 6530
Frequency of PRIDE: 53
Frequency of PREJUDICE: 11
BST Map: 0.2790993 s

pride-and-prejudice.txt
Total words: 125901
Total different words: 6530
Frequency of PRIDE: 53
Frequency of PREJUDICE: 11
Linked List Map: 14.0617589 s

看看耗时,可想而知了,那么你想到了嘛。没错真相只有一个字数太多,以后少发一点。

修改后重发为啥审核时间减短

下面接着思考,为啥我们对已经发表过的文章修改,很快就能审核通过
不知道大伙有没有想到
【菲波那契数列】
f(n) = f(n - 1) + f(n - 2) ,f(1)=1,f(0)=0。
要是
f(4) = f(3)+f(2)
= f(2)+f(1)+f(1)+f(0)
= f(1)+f(0)+f(1)+f(1)+f(0) = 3
在这里插入图片描述
看到没,这里出现很多的重复项,你的文章也是一样的道理,要是系统在重新在审核插入要多麻烦事,相信大伙都看出来了,用动态规划了吧,以此来减少时间差。
下面我们看下代码的对比。

递归求斐波那契数列

public class Solution1 {
    private int num = 0;

    public int fib( int n ){
        num ++;
        if( n == 0 )
            return 0;
        if( n == 1 )
            return 1;
        return fib(n-1) + fib(n-2);
    }

    public int getNum(){
        return num;
    }

    public static void main(String[] args) {

        int n = 42;
        Solution1 solution = new Solution1();
        long startTime = System.currentTimeMillis();
        int res = solution.fib(n);
        long endTime = System.currentTimeMillis();

        System.out.println("fib(" + n + ") = " + res);
        System.out.println("time : " + (endTime - startTime) + " ms");
        System.out.println("run function fib() " + solution.getNum() + " times.");
    }
}

这里计算的42值,就花了很长时间

结果输出
fib(42) = 267914296
time : 2214 ms
run function fib() 866988873 times.

我们再看动态规划

public class Solution2 {
    private int num = 0;

    public int fib(int n){
        int[] memo = new int[n + 1];
        Arrays.fill(memo, -1);
        return fib(n, memo);
    }

    private int fib(int n, int[] memo){
        num ++;
        if(n == 0)
            return 0;
        if(n == 1)
            return 1;
        if(memo[n] == -1)
            memo[n] = fib(n - 1, memo) + fib(n - 2, memo);

        return memo[n];
    }
    public int getNum(){
        return num;
    }
    public static void main(String[] args) {

        //int n = 42;
        int n = 1000; // 注意: 我们使用n = 1000只是为了测试性能, 实际上会溢出
                      // 斐波那契额数列是以指数速度上涨的
        Solution2 solution = new Solution2();
        long startTime = System.currentTimeMillis();
        int res = solution.fib(n);
        long endTime = System.currentTimeMillis();

        System.out.println("fib(" + n + ") = " + res);
        System.out.println("time : " + (endTime - startTime) + " ms");
        System.out.println("run function fib() " + solution.getNum() + " times.");
    }
}

这个差距呀

输出结果
fib(1000) = 1556111435
time : 0 ms
run function fib() 1999 times.

看到了吧,再次提交修改的文章审核时间大幅度减短是有原因的,要是你觉得不对,可能是你比较优秀,CSDN直接看中你多人。
这是我对审核的一点小小的思考,当然人家的算法更厉害,不可能像我这样说,时间优化肯定还要更完善。
文章至此,仅代表个人想法,要是不小心冒犯了,我会虚心接受点评的。

发布了18 篇原创文章 · 获赞 24 · 访问量 5367

猜你喜欢

转载自blog.csdn.net/weixin_43464303/article/details/105681988