CodingTour
ARTS #22

Algorithm

本周选择的算法题是:Longest Valid Parentheses

规则如下:

Given a string containing just the characters '(' and ')', find the length of the longest valid (well-formed) parentheses substring.

Example 1:

Input: "(()"
Output: 2
Explanation: The longest valid parentheses substring is "()"

Example 2:

Input: ")()())"
Output: 4
Explanation: The longest valid parentheses substring is "()()"

Solution

这题解法多且复杂,值得深挖。

Runtime:52 ms,快过 73.59%。

Memory:14.3 MB,低于 5.55%。

class Solution:
    def longestValidParentheses(self, s: str) -> int:
        stack, max_length = [-1], 0
        for i in range(len(s)):
            char = s[i]
            if char == '(':
                stack.append(i)
            else:
                stack.pop()
                if stack:
                    # 栈不是空的,括号配对成功,通过栈顶元素计算有效长度
                    max_length = max(max_length, i - stack[-1])
                else:
                    stack.append(i)
        return max_length

dp

Runtime:48 ms,快过 91.03%。

Memory:14.1 MB,低于 5.55%。

class Solution:
    def longestValidParentheses(self, s: str) -> int:
        if not s: return 0

        dp = [0] * len(s)
        for i in range(1, len(s)):
            char = s[i]
            if char == ')':
                if s[i - 1] == '(':
                    # 满足条件,至少 + 2,如果'('前还有有效长度,继续加上
                    dp[i] = (dp[i - 2] if i >= 2 else 0) + 2
                elif i - dp[i - 1] - 1 >= 0 and s[i - dp[i - 1] - 1] == '(':
                    # 满足条件,符合 (())
                    # 如果 (()) 前还有(),继续加上
                    dp[i] = dp[i - 1] + (dp[i - dp[i - 1] - 2] if i - dp[i - 1] >= 2 else 0) + 2
        return max(dp)

常量级空间复杂度

Runtime:68 ms,快过 16.94%。

Memory:13.9 MB,低于 16.67%。

class Solution:
    def longestValidParentheses(self, s: str) -> int:
        def traversal(iterator, reset_checker) -> int:
            left, right, max_length = 0, 0, 0
            for i in iterator:
                char = s[i]
                if char == '(':
                    left += 1
                else:
                    right += 1

                if left == right:
                    # 满足条件,配对成功
                    max_length = max(max_length, left + right)

                if reset_checker(left, right):
                    left, right = 0, 0
            return max_length

        return max(
            # 先从左往右
            traversal(range(len(s)), lambda left, right: right > left),
            # 再从右往左
            traversal(range(len(s)-1, -1, -1), lambda left, right: left > right)
        )

Review

What’s the Difference Between a Framework and Library? 一文读懂 Framework 和 Library 的区别。

以前端最流行的三大框架为例:Angular、Vue、React,摆事实讲道理列出了各自设计的优缺点,做一个总结。

你告诉 Library 要做什么;Framework 告诉你要做什么

Framework

以 Angular 和 Vue 为代表,它们提供了一个“最佳实践”,你只需要无脑跟即可。

优点

  • 工具链齐全(组件、状态管理、路由等)
  • 有官方的“最佳实践”,可以短时间内提高生产力
  • 容易招聘,技能统一
  • 清晰的演化路径

缺点

  • 性能降低,如果你只需要一点点功能,仍然需要所有的代码
  • 小项目不需要它,过于复杂
  • 不容易定制,如果 Framework 不提供某个支持,你很难拓展
  • 有一堆东西要学习
  • 过于舒适,也可以认为是技术栈单一

Library

以 React 为代表,你可以控制一切。

优点

  • 单一原则,React 只负责创建 UI,其他的像状态管理由 Redux 提供
  • 容易控制
  • 只增加你需要的功能,这很好理解,一个 Library 只做好一件事,拓展时只需要和其他的 Library 进行组合即可
  • 学习很多其他的工具,换个视角看,你的技术栈比较全面

缺点

  • 没有统一的架构
  • 大量的技术选型,通常你需要花很多时间在工具相同的 Library 之间进行选择
  • 仍然有一堆东西需要学习,无论是采用 Framework or Library,应用的体量、架构都会影响学习曲线
  • 潜在的升级风险,如果每次更新都使你的 Library 之间出现兼容性问题,这就是灾难

Tip

CI、CD 的核心是“频繁”,如果代码合并容易出错,那就频繁合并,如果部署很蛋疼,那就频繁部署。

在提测流程中,影响效率的还有“速度”,想象一天产生 N 个测试包,你需要多少时间来消化?在保持“频繁”的前提下还需要提高“速度”,如改善自动化测试流程等。

我们公司也采用了一种“拓展”方案来提高“速度”,我们内部把它称为 dogfood - 吃自己的狗粮。

Share

淘宝为什么能抗住双 11 ?看完这篇文章你就明白了!

思路清晰,全是干货,新(cai)手(niao)都看得懂!