Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ARTS 第十四周(2019.9.30~2019.10.6) #14

Open
catcuts opened this issue Oct 8, 2019 · 0 comments
Open

ARTS 第十四周(2019.9.30~2019.10.6) #14

catcuts opened this issue Oct 8, 2019 · 0 comments
Labels

Comments

@catcuts
Copy link
Owner

catcuts commented Oct 8, 2019

ARTS 第十四周(2019.9.30~2019.10.6)

Algorithm 报数

题目

报数

代码

/**
 * @param {number} n
 * @return {string}
 */
var countAndSay = function(n) {
    if (n === 1) return '1';  // 若 n = 1 则 返回 '1'
    let result = '1',  // 结果末尾总是 '1',故设初始的当前数字为 '1'
        lastCountAndSay = countAndSay(n - 1),  // 先获取上一个 countAndSay 结果
        lastCASLength = lastCountAndSay.length;
    // 然后再在上一个 countAndSay 结果上推断本 countAndSay,方法是:
    // 从末尾往前遍历
    for (let i = lastCASLength, j = 0; i--;) {
        let next = lastCountAndSay[i - 1];
        // 若遍历当前值与遍历下一个值不相等
        if (lastCountAndSay[i] !== next) {
            // 计算出当前数字总数
            let count = lastCASLength - i - j;
            // next 作为下一个当前数字
            result = `${next || ''}${count}${result}`;
            // 用于保存计算当前数字总数的偏移量
            j += count;
        }
    }
    return result;
};

执行结果:通过
执行用时:64 ms,在所有 JavaScript 提交中击败了 97.60% 的用户
内存消耗:35.7 MB,在所有 JavaScript 提交中击败了 28.42% 的用户

思路:
见注释:

  • n = 1 则 返回 '1'
  • 因为结果末尾总是 '1',故设初始的当前数字为 '1'
  • 然后先获取上一个 countAndSay 结果
  • 再在上一个 countAndSay 结果上推断本 countAndSay,方法是:
    • 从末尾往前遍历
    • 若遍历当前值与遍历下一个值不相等
    • 则计算出当前数字总数
    • 并把 next 作为下一个当前数字
    • 更新 j,用于保存计算当前数字总数的偏移量
      时间复杂度 = O(n);不占用额外空间,故空间复杂度 = O(1)。

对比:
与高分对比:
本代码运行 18 个测试用例花费约 64ms,平均一个测试用例约 3.6ms;
高分代码运行 18 个测试用例花费约 64ms,平均一个测试用例约 3.6ms。
附高分代码:(它是从前往后遍历)

/**
 * @param {number} n
 * @return {string}
 */
var countAndSay = function(n) {
    let result = '1';
    let prev = result[0];
    let count = 1;
    for (let i = 1; i < n; i++) {
        let newResult = '';
        for (let j = 1; j <= result.length; j++) {
            const current = result[j];
            if (current !== prev) {
                newResult += count + prev;
                prev = current;
                count = 1;
            } else {
                count++;
            }
        }
        result = newResult;
        prev = result[0];
    }
    
    return result;
};

Review JavaScript 变量引用“死区”

阅读:
Don't Use JavaScript Variables Without Knowing Temporal Dead Zone

点评:
本文介绍了 JS 在变量引用上的“死区”(Temporal Dead Zone,简称 TDZ)。

变量引用“死区”是指,在变量被声明之前引用变量会抛出 ReferenceError 错误。

存在变量引用“死区”的变量声明方式有:letconstclass

此外,在类的构造器函数中,super() 之前使用 this 也会抛错,这也算是变量引用死区。

而且,typeof 变量 也是对变量的引用,若该变量使用上述方式声明,在此之前引用也会抛出错误。

不会导致变量引用“死区”的变量声明或引用方式有:varfunctionimport

还有一点要注意的是,变量引用“死区”只在变量的作用域内有效,这里是一个比较综合的例子:

function doSomething(someVal) {
  // Function scope
  typeof variable; // => undefined 不受 if 内的“死区”影响
  if (someVal) {
    // Inner block scope
    typeof variable; // throws `ReferenceError`
    let variable;
  }
}
doSomething(true);

最后作者总结说,TDZ 对于规范的编程还是有帮助的,它避免了开发者随意使用未先声明的变量。

Tip 使用 Nodejs Dgram 模块接收组播消息的注意事项

Nodejs 提供了 Dgram 模块,用于收发 UDP 消息,也包括加入和退出组播、接收和发送组播消息。

但有一点容易被忽略,就是:当创建了一个 UPD 服务端或客户端后,如果绑定端口的同时又绑定了非组播 ip,就会收不到组播消息。

比如:

const dgram = require('dgram');
const server = dgram.createSocket('udp4');
server.bind(端口,非组播IP);  // 这样就算加入组播也接收不到组播消息(但是可以发送)

理由也很简单,就是这个 UDP 服务端或客户端监听的是往特定 IP 发送的 UDP 消息,而非往组播发送的消息。

但就是容易被忽略,造成错误排查时的疑惑。

参考:
[dgram]no udp multicast message received when binding on a specific address #1690

I've been looking into this and think it works as expected.
IIUIC, to receive a multicast datagram you have 2 options:

  • binding only to the PORT the multicast message is sent and joining the multicast group i.e.: as in receive-all-addresses.js.
    This way, you can receive every message sent to that port whether multicast or not.
  • binding to the PORT and the multicast address and joining the multicast group.
    This restricts the messages received to multicast only.
    As in receive-specific-address.js but binding to MULTICAST_IP instead of LOCAL_IP.

On the other hand, if you want to restrict from which interface the multicast messages are received
you can use the multicastInterface argument in addMembership.
For example: s.addMembership(MULTICAST_IP, LOCAL_IP);
will allow to receive multicast messages received in the LOCAL_IP interface.

Share [极客专栏] 95 | 高效学习:端正学习态度

分享一篇极客“左耳听风”专栏文章(据说可限10位免费阅读哦)
95 | 高效学习:端正学习态度

这是一篇关于如何高效学习的方法论文章,
注意是“高效学习”而非“高速学习”,
旨在:澄清学习本质,端正学习态度:

  • 学习是逆人性的,不存在轻松学习
  • 学习应是主动学习,而非被动学习
  • 学习应是深度学习,而非浅度学习
  • 学习不光是为答案,也是为找到方法
  • 学习不仅是为知道,也是为思考理解
  • 学习既为开阔眼界,也是为知己不知
  • 学习既为成长自身,也是为改变自己

学习的误区:

  • 有意识无行动
  • 想行动没目标
  • 定目标缺方法
  • 少实践欠坚持

总的来说就是:学习应该是有意识且有方法地朝既定目标持续坚持的过程。

被动学习和主动学习:

  • 被动学习:通过听讲、阅读、视听,演示,学习内容平均留存率分别为 5%、10%、20%、30%
  • 主动学习:通过讨论、实践、传授,学习内容平均留存率分别为 50%、75%、90%

这个理论告诉我们:

  • 只靠听和看这种输入式的学习方法,效率是不高的
  • 在输入式学习的基础上,采取输出式学习,则可以很大提升效率

浅度学习和深度学习:

  • 浅度学习:从表面或加工过的材料中获得知识,并且浅尝辄止,只留个印象,属于消费内容
  • 深度学习:从源头查看第一手资料中获取知识,并且深度钻研,经自身转化,属于生产内容

深度学习的关键在于:

  • 获取高质量的信息源和第一手的知识(阅读原著、官方文档、原作者书籍)
  • 把知识连成地图,反述出自己的理解
  • 不断反思和思辨,与不同年龄人讨论
  • 举一反三并践行,将知识转化为技能

由此可见深度学习的三个步骤:

  • 知识采集
  • 知识缝合
  • 知识转化
@catcuts catcuts added the ARTS label Oct 8, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

1 participant