# 第七十三周ARTS总结

# Algorithm

0ms | 100.00% Run time
39MB | 95.06% Memory

public List<TreeNode> generateTrees(int n) {
    List<TreeNode> pre = new ArrayList<>();
    List<TreeNode> cur = new ArrayList<>();

    for (int i = 0; i < n; i++) {
        cur.clear();

        if (i == 0) {
            // 找到长度为1的所有树
            TreeNode treeNode = new TreeNode(i + 1);
            cur.add(treeNode);
        } else {
            // 找到长度大于1的所有树
            // 1. 新增的节点是根节点
            // 2. 新增的节点插入到 根节点 和 右树 之间,原右树为新增加点的左树
            // 3. 新增的节点插入到 右树 和 右树的右树 之间
            // 4. ...
            for (int j = 0; j < pre.size(); j++) {
                // 需要往preItem中插入新的节点
                TreeNode preItem = pre.get(j);

                // 新增的节点为根节点
                TreeNode root = new TreeNode(i + 1);
                root.left = preItem;
                cur.add(root);

                // 新增的节点在右边(k代表第k个right)
                int k = 0;
                loop:
                while (true) {
                    TreeNode rootCopy = cloneTree(preItem);
                    TreeNode right = rootCopy;

                    // 找到第k个right,找不到的话就结束遍历
                    for (int m = 0; m < k; m++) {
                        if (right.right != null) {
                            right = right.right;
                        } else {
                            // 找不到第k个right,结束while循环
                            break loop;
                        }
                    }

                    TreeNode insertNode = new TreeNode(i + 1);
                    insertNode.left = right.right;
                    right.right = insertNode;
                    cur.add(rootCopy);

                    k++;
                }
            }

        }

        pre.clear();
        pre.addAll(cur);
    }

    return cur;
}

/**
 * 因为左树不涉及到改变,所以只需要完全复制右树
 *
 * @param treeNode
 * @return
 */
private TreeNode cloneTree(TreeNode treeNode) {
    TreeNode clonedTree = new TreeNode(treeNode.val);
    clonedTree.left = treeNode.left;

    if (treeNode.right != null) {
        clonedTree.right = cloneTree(treeNode.right);
    }

    return clonedTree;
}

public static class TreeNode {
    int val;
    TreeNode left;
    TreeNode right;

    TreeNode() {
    }

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

    TreeNode(int val, TreeNode left, TreeNode right) {
        this.val = val;
        this.left = left;
        this.right = right;
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96

0ms | 100.00% Run time
35.7MB | 66.59% Memory

public int numTrees(int n) {
    // key为树的长度,value为一共有多少种结构
    Map<Integer, Integer> map = new HashMap<>();
    map.put(0, 1);
    map.put(1, 1);
    map.put(2, 2);

    for (int i = 3; i <= n; i++) {
        int sum = 0;

        // 计算根节点是1,2,3...i的时候,一共有多少种方式
        for (int j = 1; j <= i; j++) {
            sum = sum + map.get(j - 1) * map.get(i - j);
        }

        map.put(i, sum);
    }

    return map.get(n);
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20

# Review

# Tip

  • Linux进程间通信方式
    • 管道
    • 消息队列
    • 共享内存
    • 套接字
    • 信号量
    • 信号
  • Android通信方式
    • Binder
    • Socket
    • Handler
  • APK瘦身计划
    • so指定平台
    • 删除冗余资源
    • 图片压缩
    • 重复资源优化
    • 资源混淆
    • 指定语言
    • 三方库精简
    • R文件内联
    • 混淆
  • 性能优化衡量指标
    • APK包大小
      • 指标:APK包的大小
    • APK冷启动速度
      • 指标:从Application#attach到第一个页面完全加载完的时间
    • ANR的分析
      • 指标:给Looper发送一个事件,5s后检测事件是否执行
    • 卡顿分析
      • 指标:给Looper设置mLogging,检测每一个事件的处理时间
    • 内存优化
      • 指标:利用AndroidStudioProfiler工具
  • Linux进程切换流程
    • 10ms一次的定时器
    • 触发定时器会给CPU一个中断信号
    • 中断信号会使CPU寻找中断向量表,最终找到并执行do_timer
    • do_timer会将当前进程的counter减一,如果仍大于0则结束
    • 等于0时开始调度
    • 找到所有RUNNABLE进程,并找到counter最大的那个进程(counter都为0则重新赋值)
    • 通过switch_to函数切换进程
    • 进行下一次滴答

# Share

暂无内容

更新时间: 10/20/2022, 7:04:01 AM