Algorithm
本周选择的算法题是:Concatenation of Array。
规则
Given an integer array nums
of length n
, you want to create an array ans
of length 2n
where ans[i] == nums[i]
and ans[i + n] == nums[i]
for 0 <= i < n
(0-indexed).
Specifically, ans
is the concatenation of two nums
arrays.
Return the array ans
.
Example 1:
Input: nums = [1,2,1]
Output: [1,2,1,1,2,1]
Explanation: The array ans is formed as follows:
- ans = [nums[0],nums[1],nums[2],nums[0],nums[1],nums[2]]
- ans = [1,2,1,1,2,1]
Example 2:
Input: nums = [1,3,2,1]
Output: [1,3,2,1,1,3,2,1]
Explanation: The array ans is formed as follows:
- ans = [nums[0],nums[1],nums[2],nums[3],nums[0],nums[1],nums[2],nums[3]]
- ans = [1,3,2,1,1,3,2,1]
Constraints:
n == nums.length
1 <= n <= 1000
1 <= nums[i] <= 1000
Solution
class Solution:
def getConcatenation(self, nums: List[int]) -> List[int]:
n = len(nums)
ans = [0] * 2 * n
for i in range(n):
ans[i] = ans[i + n] = nums[i]
return ans
Review
重新 Review 了一篇旧文:I never understood JavaScript closuers。
绝对不是标题党!总结得非常好!
总结下:
Local execution context,局部执行上下文
Global execution context,全局执行上下文
Function = definition + closure,作者用的背包比喻很恰当,函数作用域内被捕获的变量存放到了一个背包中,这个背包和函数定义是绑定在一起的,JS 寻找变量时,按以下顺序寻找:
- 背包 -> Local execution context -> Global execution context
其中 Local execution context 的生命周期自然就是函数的进栈和出栈
顺便提下 Swift 的 Closures 和 Objective-C 的 Blocks:
- 首先它们是兼容的,这意味着你可以传递 Closures 给 OC 方法
- 因为 Swift 的 Functions 和 Closures 是相同的类型,所以你也可以传递 Functions
- Swift 的变量是可变而不是复制的,换句话说,OC 的 __block 在 Swift 里是默认的行为
Tip
在组织项目复盘的过程中,自己成了最大的受益者,知道了一个跨团队的项目要如何去推动,甚至可以形成方法论:
- 梳理目标,并根据目标制定核心技术方案
- 对齐目标,并将所有链路上的同学拉在一起做 face to face 的确认
- 定期 review 并同步项目进展,控制风险以及调整优先级
- 上线后组织复盘,让参与的同学获取成就感,同时分析问题和原因,制定改进计划
Share
早年从阮一峰的文章 Paul Graham:撼动硅谷的人(译文) 了解到 黑客与画家 这本书,但过去一直“没有”机会完整的读完,最近这一年的阅读量相比往年提高了许多,也是在这一年读完了黑客与画家。
Paul Graham 身份是黑客、创业者、投资人,但在我看来更像是一个思想家,这本书充满了真知灼见,内涵丰富,创业者必读。Graham 有他独特的财富观,而且鼓励创业,虽然在人类历史上,财富的名声曾经一直不太好,但在现代社会,要获取财富最佳的途径还是要靠自己创业。
Graham 在书中谈到了“创业的方法论”,比如:
眼下想必每个人都知道,过早优化(premature optimization)是一件危险的事情。我认为,我们应该对“过早设计”(premature design)也抱有同样的担忧,不要太早决定一个程序应该怎么做。
合适的工具能够帮助我们避免这种危险。一种好的编程语言,应该像油画颜料一样,能够使得我们很从容地改变想法。动态类型语言在这一点上就是赢家,因为你不必提前就设置好各种变量的数据类型。不过我认为,编程语言灵活性的关键还不在这里,而在于这种语言应该非常抽象。最容易修改的语言就是简短的语言。
“最好的文字来自不停的修改”,其实无论做什么“产品”,都要追求可迭代这个原则,开公司、写代码、做设计也是一样,设计一样东西,最重要的一点就是要经常“再设计”,编程尤其如此,再多的修改都不过分,走进死胡同和放进垃圾堆没有任何区别。Graham 同样也在书中告诉我们,无论做什么都要追求极致,来自一知半解的决策,如果不懂风险出在什么地方,往往也会把风险夸大。
Graham 还推崇乐观主义 + 怀疑倾向两种信念相结合的方式:
为了写出优秀软件,你必须同时具备两种互相冲突的信念。一方面,你要像初生牛犊一样,对自己的能力信心万丈;另一方面,你又要像历经沧桑的老人一样,对自己的能力抱着怀疑态度。在你的大脑中,有一个声音说“千难万险只等闲”,还有一个声音却说“早岁哪知世事艰”。
对解决难题的可能性保持乐观,同时对当前解法的合理性保持怀疑,当然了,如果方向不对,再怎么努力也无法到达目的地,同时,扎实的基础、毅力、效率也是成功的必备因素,否则就只能是空中楼阁、纸上谈兵,有趣的是,另一本书的书名总结了这个观点:像外行一样思考,像专家一样实践。
Graham 强调既要了解时代的规则,也要永远独立思考,显然这不是一本完全讲技术的书,它能满足非技术人员的好奇心,但作者在 IT 行业也算是能指点江山的大师,全书内容还是很赞的,希望自己有空能研究下 Lisp,同时 Make something people want!