Contents

ARST打卡第240周

Algorithm

lc2048_下一个更大的数值平衡数

思路: 1e6数据范围小,数位长度不大,可以暴力遍历构造。

以下代码有详细思路过程。

题解写法封装性更好(后文贴),还有打表二分的做法,可以自行查看LeetCode题解。

 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
class Solution {
public:
    int nextBeautifulNumber(int n) {
        // 感觉应该是首先判断数位,数位为b
        // 然后 1-b 构造最小数位
        // 最多6位数,所以甚至可以之间遍历验证。
        if (0 == n) {
            return 1;
        }
        int b = 0;
        int tmp = n;
        while (tmp) {
            b++;
            tmp /= 10;
        }
        if (b == 1) {
            return 22;
        }
        // 先暴力遍历模拟找思路,等看有没有直接方法构造
        // 这里 Mx 导致 wa了一发:
        // 解答错误 122 / 145 个通过的测试用例 , 输入 23, 输出 22,预期 122
        // 这里是当前位数用尽,所以前面加个1才行
        // int Mx = b;
        // for (int i = 1; i < b; i++) {
        int Mx = 1;
        for (int i = 1; i <= b; i++) {
            Mx = Mx * 10 + b;
        }
        vector<int> count(b + 1, 0);
        for (int i = n + 1; i <= Mx; i++) {
            int tmp = i;
            // count.clear(); // 错误清零方式
            count.assign(b + 1, 0);
            bool invalid = false;
            while (tmp) {
                int j = tmp % 10;
                if (0 == j || j > b) {
                    invalid = true;
                    break;
                }
                count[j]++;
                tmp /= 10;
            }
            if (invalid) {
                continue;
            }
            for (int k = 1; k <= b; k++) {
                if (!count[k]) {
                    continue;
                }
                if (count[k] != k) {
                    invalid = true;
                    break;
                }
            }
            if (invalid) {
                continue;
            }
            return i;
        }
        return Mx;
    }
};

题解做法:

 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
class Solution {
public:
    bool isBalance(int x) {
        vector<int> count(10);
        while (x > 0) {
            count[x % 10]++;
            x /= 10;
        }
        for (int d = 0; d < 10; ++d) {
            if (count[d] > 0 && count[d] != d) {
                return false;
            }
        }
        return true;
    }

    int nextBeautifulNumber(int n) {
        for (int i = n + 1; i <= 1224444; ++i) {
            if (isBalance(i)) {
                return i;
            }
        }
        return -1;
    }
};

Review

【TED演讲】如何辞去工作

辞去工作时的一些注意事项。这个人的发音很清晰,比较好训练听力。

Tips

iTerm2 如何设置半透明窗口?

有时候 mac 单个屏幕不够显示,需要边看书边操作,所以就可以通过设置终端透明来达到边看边操作的目的。

Share-cpp_const_cast未定义行为导致进程内存错误记录

cpp编码中,可能因为未定义行为导致进程内存错误,导致进程在后续运行时莫名其妙地coredump。 实际上是访问了之前被写坏的内存地址,导致coredump。

这种问题一般很难在运行时定位到根本原因,必须熟悉cpp语言并且对操作系统知识有了解才行。

最近就遇到了上述异常,具体原因是这样:

修改 const 对象,导致未定义行为出现在整个进程里面! How to use const_cast?

实际上就是把 const 对象的对应进程的内存写坏了,所以导致进程中的对应内存数据不可用。 导致了进程在下次访问这里的内存可能 coredump, 导致 debug 定位困难。

可以描述一下当时的诡异现象:

  • 跑的是一个单测进程,进程里面跑了超级多的单测用例
  • 整体跑单测进程的时候会在写log的时候 coredump 在一个固定的单测上
  • 但是单独跑单测用例又都能单独跑通过
    • 已经确定了每个单测前后都清理并重新初始化了应用程序逻辑上的依赖关系

实际上:

  • 前面某个单测跑cpp代码的时候,调用了 const_cast 对 const 对象写内存
  • 因为单测用例很短,所以这块进程内存写坏了也不会立马产生任何实质性地影响
  • 后续单测再访问这个进程内存时,才发现内存不可用而 coredump
  • 因此这个bug在应用程序逻辑上完全没有问题,而是编码导致了操作系统内进程内存错误…