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 #2

Open
JunQu opened this issue Apr 24, 2021 · 9 comments
Open

第一周的ARTS #2

JunQu opened this issue Apr 24, 2021 · 9 comments
Assignees
Labels
Milestone

Comments

@JunQu
Copy link
Owner

JunQu commented Apr 24, 2021

Algorithm

万事从头开始,从 leetcode 第一题 Two Sum 开始。

这个问题相信不必多说,毕竟第一题,我说一下可能需要注意的点

  • 数组不是排序的
  • 数字可能重复
  • 如果没有结果他(leetcode)是会抛出错误

暴力法

直接遍历所有可能性,然后找到相符合的目标(target),那么代码就是:

const twoSum = (nums, target) => {
  for (let i = 0; i < nums.length; i++) {
    for (let j = i + 1; j < nums.length; j++) {
      if (nums[i] + nums[j] === target) {
        return [i, j];
      }
    }
  }
}

暴力法其实并不是一开始想到办法,因为时间复杂度是 O(n*n) 这个在很多时候是不能接受的。
当然在这道题其实是可以接受的,因为题目条件范围是 2 <= nums.length <= 10**3,即使是最大的情况下 10**6 相对来说也不是特别大,果然我的提交验证了我的想法。
Screen Shot 2021-04-24 at 11 40 18 PM

双指针

学习数据结构的时候,老师曾提醒过,当遇到 O(n * n) 的情况,很多时候都是可以优化成 O(n*logn),这是一个相对可以接受的复杂度。也是我一开始的想法,拿到这个就想到有没有可能一遍过。如果是 O(n*logn) 那么首先考虑的就是排序,因为排序一般期望的复杂度就是O(n*logn),既然排序了,那么数字是从小到大的,而且确定了目标值(target),从两端或者从中间的方法,双指针的想法也就自然而然的想到了。
于是双指针的解法如下:

const twoSum = (nums, target) => {
    const copyNums = nums.slice(0);
    const sortedNums = nums.sort((a,b)=>a-b);
    let leftPoint = 0;
    let rightPoint = sortedNums.length - 1;
    while (leftPoint < rightPoint) {
      const sum = sortedNums[leftPoint] + sortedNums[rightPoint];
      if (sum > target) {
        rightPoint--;
      } else if (sum < target) {
        leftPoint++;
      } else {
        break;
      }
    }
    if(leftPoint===rightPoint) {
      return undefined;  // not find
    }
    const leftValue = copyNums.indexOf(sortedNums[leftPoint]);
    const rightValue = copyNums.lastIndexOf(sortedNums[rightPoint]);
    return [leftValue, rightValue];
};

这一次时间上就超过了 80.29% 相对暴力法的 6.45% 进步了不少。

一次遍历

如果说 n 个元素,一般认为最好期望是 o(n)。在 O(1) 这样的复杂度通常是非常消耗空间的情况,而 O(logn)往往是特殊的数学技巧或者方法,我目前能做的就是尽量是在O(n)的复杂度。那么这个有没有可能 O(n),还是有的。通过空间换取时间,我们回想目标(target),假如我们确定了一个值,是不是也同时确定了另一个值,于是我们可以通过记住所有的值来判断有没有另一个我们要找的值。所以可以通过构造一个哈希字典记住之前的值和索引,记住值是为了方便判断是否存在,记住索引是为了返回。得到这个思路,我们可以一次遍历就能得出结果。

const twoSum = (nums, target) => {
 const map = new Map();
 for (let i = 0; i < nums.length; i++) {
   const key = target - nums[i];
   if (map.has(key)) {
     return [map.get(key), i];
   } else {
     map.set(nums[i], i);
   }
 }
};

因为哈希字典的存取视为 O(1),这一次整体的复杂度就是 O(n),终于到达了想要的最佳期望。不过在上面的提交后时间并不快,甚至比双指针慢,可能是leetcode的原因。而且看了最佳答案发现还有个点可以优化,map.has 换成 map.get想想也是会快一点,不过我不准备换了,因为这样更容易看懂一些。

BTW

可能是 js 的强大 v8 或者 leetcode 的关系,可能你会发现 for 循环有时候甚至不如 forEach map 这些快,只能佩服v8的优化,但是我应该不会选择这些,尽量少用 js 特性而去纯粹的刷题, 尽量去用最原始的方式就是我的一个方式,即大概我不会使用一行代码去解决了。每个人追求目标或许相同,但是每个人经过的路途可以不同。

@JunQu
Copy link
Owner Author

JunQu commented Apr 24, 2021

Review

原文链接:core-web-vitals
Web Vitals 适用于所有网页的性能检测,而 Core Web Vitals 是属于Web Vitals的一部分。Core Web Vitals 应该是由网站的所有者自己测量,并且可以通过所有(相关的)Google工具呈现。每个Core Web Vital代表着用户体验的不同方面,可以现场测试,反映了用户真实体验的重要结果。 Core Web Vitals 的指标会随着时间的增长而不断变化,当前2020年的指标关注用户体验的三个方面:页面加载,页面交互性,视觉稳定性。包含接下来的指标(及其阈值)。
最大内容绘制时间(LCP):(这项指标)衡量页面加载的性能。为了给用户一个更好的体验,LCP应该在页面首次开始加载后的2.5秒内开始。
第一次输入延迟时间(FID):(这项指标)衡量页面可交互性。为了给用户一个更好的体验,页面的FID应当不超过100毫秒。
累计页面布局的变化(CLS):(这项指标)衡量页面视觉稳定性。为了给用户一个更好的体验,页面应当保持CLS的值不超过0.1。

为什么翻译这个?
因为最近 Web Vitals 包已经发布正式版 1.1.1了,而且被 create-react-app 内置,我很看好他以用户体验衡量页面性能的方式。

单词
非常多不认识的,也不好翻译的词,导致翻译的让人看不懂。
measured 慎重的,经过仔细思考的。
surfaced 表层,表面,外层。
distinct 明显的,显著的,确实的
critical 批判的,关键的,重大的,挑剔的,严厉的
outcome结果,后果,效果
interactive交互,互动

@JunQu
Copy link
Owner Author

JunQu commented Apr 24, 2021

Tip

|| vs ?? in JavaScript

在js中:
||: 逻辑运算符,如果左边的值为 Falsy 则返回右边的值。
??:空值合并运算符,左边为null或者undefined 则返回右边的值。

看描述就会有很多的区别,其实他们是相关的,从范围来看 ?? 属于 ||

const a = undefined || 'a';
const b = null || 'b';
const c = undefined ?? 'c';
const d = null ?? 'd';
console.log(a,b,c,d); // a b c d

而因为推出了可选操作符?. 导致了一些联动例如 a?.b?.c ?? d 这个如果 a b c 无论哪一个是undefined 或者 null 都会返回 d,这样保证了安全的访问和默认值。所以现在很多之前写默认值的通过||也可以转为更好的??
但是如果你有更多的选择,比如我希望金额为0时,显示为 0.00,可以写成 product?.price || '0.00'.

这两个操作符有部分重叠,我们可以挑选更好的方式完成我们的目标,不只纯粹的只用某一个。

@JunQu
Copy link
Owner Author

JunQu commented Apr 24, 2021

Share

思维分享

投资和治癌的相似之处:想要不被癌症杀死,最有效的办法,是降低自己生癌的概率。简而言之就是不吸烟,不喝酒,不熬夜,坚持锻炼,饮食健康,劳逸结合。这些方法没啥秘密可言,你也不需要花钱去买,但是它们听起来很无聊,而且要长期坚持。然而大家最感兴趣的,却是那些能够治愈癌症的特效药。最好是几个月就能把癌细胞杀死,让病人起死回生。问题在于,全世界最聪明的科学家们研究了几十年,还是没有找到这样的特效药。
投资也是类似。多元分散,控制成本,长期坚持,搞懂了这几个原则并且耐心坚持的话,你的投资回报不会太差,而且不太可能爆仓而蒙受重大损失。但是很多人觉得这样的方法太无聊,太没有挑战性,致富太慢。他们宁愿铤而走险,追求能够让他们一夜致富的特效投资方法,却没有意识到自己只是在捞水中月而已。
伍治坚的知乎想法

这是影响我四月判断的想法,周围朋友同学都买基金、股票,甚至炒币,而我一直未曾尝试去投资理财,当然主要原因是没钱,现在我也记下了,好好的健身、睡觉,慢慢的积累起来。

技术分享:

商业项目如何选择框架: https://mp.weixin.qq.com/s/Enrfxoi4xbftoKCEiFi01Q
前端的内存优化:https://mp.weixin.qq.com/s/_wbP0B3EiTjME9Sg3BXqqA
张鑫旭的js视频解码: https://www.zhangxinxu.com/wordpress/2021/04/js-video-decode-jsmpeg-broadway/
如何使用 React devtool 检测你react网页的性能:https://blog.asayer.io/the-definitive-guide-to-profiling-react-applications

@JunQu JunQu self-assigned this Apr 24, 2021
@JunQu JunQu added the ARTS label Apr 24, 2021
@JunQu JunQu added this to the April milestone Apr 24, 2021
@JunQu
Copy link
Owner Author

JunQu commented Apr 25, 2021

靡不有初 鲜克有终

间歇性踌躇满志,持续性混吃等死,多次学习都被我放弃,希望能坚持至少一年。

第一篇完成的比较随意,不知如何去做,可能已经在悠闲的环境太久,我需要改进一些问题。

@Lijie0981
Copy link

简单看了下web vitals 的源码,感觉后面可以讲解下。Performance Api 以及为啥包体积这么小(~1K)。
Tips 不错,之前也看过 ??的文章,不过没有用过,一般都用 ||。
记得之前有篇文章里面说,不太建议写短路语句。具体原因是因为短路意义会和判断语句造成混淆。

Share 内容也很不错,不过认同和做到是两回事。做到太难了,人很懒,天生会想要去做一些一本万利的事情。客服自己人性的弱点,才能不成为普通人。我们的坚持也是。
算法的内容我现在还没太能投入思考,会有主观的恐惧。还是要练习,并面对。

@JunQu
Copy link
Owner Author

JunQu commented Apr 25, 2021

@Lijie0981

web vitals 体积确实很小,因为它检测的值也不是很多,可能大多是一些调用了浏览器API来实现所以体积小,我目前也有使用。关于源码部分确实可以看看,毕竟已经正式版本了,这个倒是也是给了我一个思路,我想以后试试它的源码当作 ts 的练手。

关于可选链操作符?.其实可以试试,因为它解决的是一些语法上某些优雅的问题,
如果不同可选链接

if (bigObject && 
    bigObject.prop1 != null && 
    bigObject.prop1.prop2 != null) {
  let result = bigObject.prop1.prop2.value;
}

对比用了可选链操作符:

 let result = bigObject?.prop1?.prop2?.value

显然可以看出冗余程度和对视觉友好度。而且它就像 async/await 一样,抄的隔壁 c# 的,js 抄的语法大多是不错的。不过如果配合三目运算确实会让人有点疑惑,类似下面的代码:

const result = !foo?.bar ? other?.value : theOther?.value ?? 'default';

几乎没人一眼就能看懂这些,就像函数式编程一样的令人费解的解读一行代码,但是这是人为的与三目运算混搭,人为的混淆可能只为某些炫技,如果写成 if/else 照样挺不错的,我们也可以把它加上一些括号进行区分。而且大多时候我认为这个语法糖挺甜的,不然很多深层次属性的访问判断写起来让人很不爽。最后语法糖几乎是进步的,是时代各类语言互相“借鉴”的优秀结果。而js自身的 private 属性就挺让人难受和本身也有点奇怪,明明好的不抄,非要自己弄个独特的 private 。

算法我也不会,对算法我就那三板斧,全用在 towSum 上了,不过必须得练起了。不过我感觉你们算法应该是信手拈来呀,大厂面试先上算法开胃,算法有想法可以交流起来。

@Lijie0981
Copy link

是的,一般情况下,代码的可读性排第一位。

@JunQu
Copy link
Owner Author

JunQu commented Apr 25, 2021

所以这个就用来访问属性就好,别与不好读懂的三目运算混搭,混搭了也要加括号区分

@tinaxu-come-on
Copy link

算法那些对于前端来说还是用的比较少,可能也是没有比较复杂的场景,数据处理都在后端了,如果放在前端对于性能还是有些影响。

|| vs ?? 这种我还是比较倾向写|| ,??我估计自己写出来,等后面看代码还得研究到底是什么意思 ,下次遇到可用的场景可以试试。

关于性能方面,没有过多的去研究,我们现在的项目都没有要求,我觉得代码写的健壮,易扩展就已经很不错了。

关于生活,多运动,身体健康比什么都强。

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

3 participants