My first post
+ + ++
diff --git a/2020/06/18/My-first-post/index.html b/2020/06/18/My-first-post/index.html new file mode 100644 index 0000000..4b62b7a --- /dev/null +++ b/2020/06/18/My-first-post/index.html @@ -0,0 +1,730 @@ + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + +一般编程语言支持通过以下几种方式来解决具体的问题:
+一般语言设计者在设计语言时,会选择侧重强调一种特定的编程方式,但这会让以不同方式来编写程序变得困难。因此有些语言就被设计成多范式语言,用以支持以上几种不同的编程方式。其中Lisp,C++ 和 Python 都是多范式语言;使用这些语言,你可以编写主要为过程式,面向对象或者函数式的程序和函数库。在大型程序中,不同的部分可能会采用不同的方式编写;比如 GUI 可能是面向对象的而处理逻辑则是过程式或者函数式。
+这篇文章主要是来讲解函数式编程,因此接下来主要围绕函数式编程进行展开。
+函数式编程:即为给定输入,输入会流经一系列函数,每个函数接收输入并输出结果。并且这个过程,在每个函数内部并不会修改全局变量或者有其他副作用。函数式编程允许把函数本身作为参数传入另一个函数,还允许返回一个函数。
+函数式风格有其理论和实践上的优点:
+这篇文章主要是讲解一些函数式编程常用的模块,比如:itertools
, functools
以及operator
。
在函数式编程中,我们经常需要把算术运算符当作函数使用,因此可以借助operator模块。operator 模块提供了一套与Python的内置运算符对应的高效率函数。例如,operator.add(x, y) 与表达式 x+y 相同。
+operator 模块为多个算术运算符提供了对应的函数,从而避免编写lambda a, b: a * b
这种平凡的匿名函数。这两种做法具体如下:
lambda a, b: a * b
匿名函数来计算阶乘:1 |
|
operator.mul
函数来计算阶乘:1 |
|
operator 模块中还有一类函数,能替代从系列中取出元素或读取对象属性的lambda表达式:
+ + +题目描述:
+++输入两个单调递增的链表,输出两个链表合成后的链表,当然我们需要合成后的链表满足单调不减规则。
+
解法一思路:
使用迭代的方法。先判断临界情况,依次判断输入的两个链表是否为空指针,如果有其中一个为空指针链表,则返回另一个有序的链表。
然后初始化一个新链表,依次比较两个有序链表的值,哪个链表的值较小,则新链表的指针指向该值。继续循环,依次比较,最终返回单调递增的新链表。
+1 |
|
解法二思路:
使用递归的方法。大体思路同上,先判断临界情况,依次判断输入的两个链表是否为空指针,如果有其中一个为空指针链表,则返回另一个有序的链表。
然后依次比较两个有序链表的值,哪个链表的值较小,则将该节点赋值给新链表。使用递归,直至其中一个链表为None,最终返回和并得到的单调递增链表。
+ +1 |
|
代码测试:
+1 |
|
题目描述:
+++输入一个链表,输出该链表中倒数第k个结点。
+
解法一思路:
+1 |
|
解法二思路:
+1 |
|
代码测试:
+1 |
|
题目描述:
+++输入一个链表,反转链表后,输出新链表的表头。
+
解法思路:
+1 |
|
代码测试:
+1 |
|
题目描述:
+++输入一个链表,按链表从尾到头的顺序返回一个ArrayList。
+
解法思路:
+1 |
|
代码测试:
+1 |
|
题目描述:
+++将一个字符串转换成一个整数,要求不能使用字符串转换整数的库函数。 数值为0或者字符串不是一个合法的数值则返回0
+
输入描述:
输入一个字符串,包括数字字母符号,可以为空
输出描述:
如果是合法的数值表达则返回该数字,否则返回0
++示例:
+
输入:
+2147483647
1a33
输出:
2147483647
0
解法思路:
使用了一个很巧妙的方法,用一个字典将字符串”0”-“9”与数字0 - 9做一个映射,然后再用数学上计算一个数字的公式得出这个数。比如:123 = (1 * 10 + 2 ) * 10 + 3
。需要注意字符串开头的正负号,从而判断得到的数字是整数还是负数。
1 |
|
代码测试:
+1 |
|
题目描述:
+++大家都知道斐波那契数列,现在要求输入一个整数n,请你输出斐波那契数列的第n项(从0开始,第0项为0,第1项是1)(n<=39)。
+
解法一思路:
直接根据数学公式f(n) = f(n - 1) + f(n - 2)
,截至条件是当n = 1, f(n) = 1
,n = 0, f(0) = 0
。利用递归法进行求解,这种方法时间复杂度很大,为O(n^2)
,空间复杂度为O(1)
。
1 |
|
解法二思路:
+1 |
|
解法三思路:
+1 |
|
代码测试:
+1 |
|
题目描述:
+++写一个函数,求两个整数之和,要求在函数体内不得使用+、-、*、/四则运算符号。
+
解法思路:
+1 |
|
代码测试:
+1 |
|
题目描述:
+++输入一个整数,输出该数32位二进制表示中1的个数。其中负数用补码表示。
+
解法思路:
+ +1 |
|
代码测试:
+1 |
|
题目描述:
+++输入一个字符串,按字典序打印出该字符串中字符的所有排列。例如输入字符串abc,则打印出由字符a,b,c所能排列出来的所有字符串abc,acb,bac,bca,cab和cba。
+
++输入一个字符串,长度不超过9(可能有字符重复),字符只包括大小写字母。
+
解法思路:
+1 |
|
代码测试:
+1 |
|
题目描述:
+++求1+2+3+…+n,要求不能使用乘除法、for、while、if、else、switch、case等关键字及条件判断语句(A?B:C)。
+
解法思路:
+1 |
|
代码测试:
+1 |
|
题目描述:
+++给定一个数组A[0,1,…,n-1],请构建一个数组B[0,1,…,n-1],其中B中的元素B[i]=A[0]A[1]…A[i-1]*A[i+1]…*A[n-1]。不能使用除法。(注意:规定B[0] = A[1] * A[2] * … * A[n-1],B[n-1] = A[0] * A[1] * … * A[n-2];)
+
解法思路:
+1 |
|
代码测试:
+ + +题目描述:
+++输入某二叉树的前序遍历和中序遍历的结果,请重建出该二叉树。假设输入的前序遍历和中序遍历的结果中都不含重复的数字。例如输入前序遍历序列 [1,2,4,7,3,5,6,8] 和中序遍历序列 [4,7,2,1,5,3,8,6] ,则重建二叉树并返回。
+
解法思路:
使用递归的方法求解。这道题需要对二叉树的性质比较了解,需要熟悉二叉树的几种遍历方式。
前序遍历是先遍历根节点,然后遍历左节点,最后遍历右节点(根左右)
+中序遍历是先遍历左节点,然后遍历根节点,最后遍历右节点(左根右)
+后序遍历是先遍历左节点,然后遍历右节点,最后遍历根节点(根左右)
+本题给定前序遍历以及中序遍历的序列,可以知道前序遍历第一个值一定是根节点。而根节点在中序遍历中会把左右子树分成两半。因此本题的关键是找到根节点,然后将左右子树依次递归重建得到二叉树。
+使用递归是需要结束条件的,当前序或中序遍历序列为None
时,便可推出递归,得到二叉树。
1 |
|
本题只需写好reConstructBinaryTree
这个方法,上面代码其他三个函数是用来前序、中序以及后序遍历重建得到二叉树的,以方便大家调试。
代码测试:
1 |
|
题目描述:
+++操作给定的二叉树,将其变换为源二叉树的镜像。
+
二叉树的镜像定义如下:
源二叉树
+ 8
+ / \
+ 6 10
+ / \ / \
+5 7 9 11
+
+镜像二叉树
+ 8
+ / \
+ 10 6
+ / \ / \
+11 9 7 5
解法思路:
+1 |
|
代码测试:
+1 |
|
题目描述:
+++输入一个整数数组,判断该数组是不是某二叉搜索树的后序遍历的结果。如果是则输出Yes,否则输出No。假设输入的数组的任意两个数字都互不相同。
+
解法思路:
+1 |
|
代码测试:
+1 |
|
题目描述:
+++给你一根长度为n的绳子,请把绳子剪成整数长的m段(m、n都是整数,n>1并且m>1,m<=n),每段绳子的长度记为 k[1],…,k[m]。请问 k[1]x…xk[m] 可能的最大乘积是多少?例如,当绳子的长度是8时,我们把它剪成长度分别为2、3、3的三段,此时得到的最大乘积是18。
+
++输入:8
+
输出:18
解法思路:
+代码测试:
+ + +题目描述:
+++一只青蛙一次可以跳上1级台阶,也可以跳上2级。求该青蛙跳上一个n级的台阶总共有多少种跳法(先后次序不同算不同的结果)。
+
解法思路:
+ +1 |
|
代码测试:
+1 |
|
题目描述:
+++一只青蛙一次可以跳上1级台阶,也可以跳上2级……它也可以跳上n级。求该青蛙跳上一个n级的台阶总共有多少种跳法。
+
解法思路:
+1 |
|
代码测试:
+1 |
|
题目描述:
+++我们可以用21的小矩形横着或者竖着去覆盖更大的矩形。请问用n个21的小矩形无重叠地覆盖一个2*n的大矩形,总共有多少种方法?
+
解法思路:
+1 |
|
代码测试:
+1 |
|
题目描述:
+++输入两个整数序列,第一个序列表示栈的压入顺序,请判断第二个序列是否可能为该栈的弹出顺序。假设压入栈的所有数字均不相等。
+
例如序列1,2,3,4,5是某栈的压入顺序,序列4,5,3,2,1是该压栈序列对应的一个弹出序列,但4,3,5,1,2就不可能是该压栈序列的弹出序列。
(注意:这两个序列的长度是相等的)
解法思路:
+1 |
|
代码测试:
+ + +题目描述:
+++把一个数组最开始的若干个元素搬到数组的末尾,我们称之为数组的旋转。
+
输入一个非递减排序的数组的一个旋转,输出旋转数组的最小元素。
例如数组{3,4,5,1,2}为{1,2,3,4,5}的一个旋转,该数组的最小值为1。
NOTE:给出的所有元素都大于0,若数组大小为0,请返回0。
解法思路:
这题主要是考察二分查找。二分查找,又叫折半查找。它的前提是线性表中的数据必须是有序的,线性表必须采用顺序存储。主要思想是:在有序表中,去中间记录作为比较对象,若给定值与中间记录的关键字相等,则查找成功;若给定值小于中间记录的关键字,则在中间记录的左半区继续查找;若给定值大于中间记录的关键字,则在中间记录的右半区继续查找;不断重复上述过程,直至查找成功,或所有查找区域无记录,查找失败为止。
上面介绍了二分查找的主要思路,而本题难点在于找到中间值与谁进行比较? 再认真审下题,给定的是非递减排序的数组,也就是“平序”或升序。例如:[1, 2, 3, 3, 3, 5, 6]
(“平序”),[1, 2, 3, 4, 5, 6]
(升序)。然后再做旋转得到旋转数组[3, 3, 5, 6, 1, 2, 3]
,[4, 5, 6, 1, 2, 3]
,可以确定的是旋转后的数组nums[0] >= nums[-1]
恒成立。
这样也就得到了nums[mid]
与哪个值进行比较了,当然是:
nums[mid] > nums[left]
, 这个时候 left = mid + 1
nums[mid] < nums[right]
, 这个时候 right = mid
nums[mid] = nums[right]
, 这个时候 left += 1
这里可以一定意义上认为nums[left]
与nums[right]
近似相等,这样便于理解。
++ +注: 以上
+nums
代表传入的旋转数组,left
指数组的第一个数,right
指数组末尾的数,mid
指数组中间位置的数。
1 |
|
代码测试:
+1 |
|
题目描述:
+++操作给定的二叉树,将其变换为源二叉树的镜像。
+
二叉树的镜像定义如下:
源二叉树
+ 8
+ / \
+ 6 10
+ / \ / \
+5 7 9 11
+
+镜像二叉树
+ 8
+ / \
+ 10 6
+ / \ / \
+11 9 7 5
解法思路:
+1 |
|
代码测试:
+1 |
|
题目描述:
+++输入一个整数数组,判断该数组是不是某二叉搜索树的后序遍历的结果。如果是则输出Yes,否则输出No。假设输入的数组的任意两个数字都互不相同。
+
解法思路:
+1 |
|
代码测试:
+1 |
|
题目描述:
+++给你一根长度为n的绳子,请把绳子剪成整数长的m段(m、n都是整数,n>1并且m>1,m<=n),每段绳子的长度记为 k[1],…,k[m]。请问 k[1]x…xk[m] 可能的最大乘积是多少?例如,当绳子的长度是8时,我们把它剪成长度分别为2、3、3的三段,此时得到的最大乘积是18。
+
++输入:8
+
输出:18
解法思路:
+代码测试:
+ + +题目描述:
+++输入一个矩阵,按照从外向里以顺时针的顺序依次打印出每一个数字,例如,如果输入如下4 X 4矩阵: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 则依次打印出数字1,2,3,4,8,12,16,15,14,13,9,5,6,7,11,10.
+
解法思路:
这道题刚开始自己一看,就是想着设置一些索引位置,按照索引位置打印来打印不就行了。后来再认真读题,发现它输入的二维矩阵大小是变化的,不是固定大小,才发现自己的想法太native
。
看了下讨论区,发现只是需要确定几个固定位置的索引值,便可以不管输入矩阵的大小,自适应的便能够确定顺时针打印每个位置的索引,然后再根据这个索引来打印矩阵就行,还真是巧妙。其实在确定好几个顶点的位置,也就相当于确定了方向,然后不管是顺时针还是逆时针,下次都可以方便的解题了。
+ +1 |
|
代码测试:
+1 |
|
题目描述:
+++输入一棵二叉树,求该树的深度。从根结点到叶结点依次经过的结点(含根、叶结点)形成树的一条路径,最长路径的长度为树的深度。
+
解法思路:
+1 |
|
代码测试:
+1 |
|
题目描述:
+++从上到下按层打印二叉树,同一层结点从左至右输出。每一层输出一行。
+
解法思路:
+1 |
|
代码测试:
+1 |
|
题目描述:
+++请实现一个函数按照之字形打印二叉树,即第一行按照从左到右的顺序打印,第二层按照从右至左的顺序打印,第三行按照从左到右的顺序打印,其他行以此类推。
+
解法思路:
这道题其实是昨天最后一道题JZ60
的升级版,其实也就是层次遍历二叉树(BFS)。层次遍历思想可以参见上一道题,只是此题需要结合二叉树的深度depth
进行解题。在每次需要打印的地方,当深度depth
对2取余,为0则从左到右打印,为1则反转打印。
1 |
|
代码测试:
+1 |
|
题目描述:
+++请实现一个函数,用来判断一棵二叉树是不是对称的。注意,如果一个二叉树同此二叉树的镜像是同样的,定义其为对称的。
+
解法思路:
+ +1 |
|
代码测试:
+1 |
|
题目描述:
+++给定一个二叉树和其中的一个结点,请找出中序遍历顺序的下一个结点并且返回。注意,树中的结点不仅包含左右子结点,同时包含指向父结点的指针。
+
解法思路:
+1 |
|
代码测试:
+1 |
|
题目描述:
+++输入一棵二叉树,判断该二叉树是否是平衡二叉树。
+
++在这里,我们只需要考虑其平衡性,不需要考虑其是不是排序二叉树
+
解法思路:
+1 |
|
代码测试:
+1 |
|
题目描述:
+++给定一个数组和滑动窗口的大小,找出所有滑动窗口里数值的最大值。例如,如果输入数组{2,3,4,2,6,2,5,1}及滑动窗口的大小3,那么一共存在6个滑动窗口,他们的最大值分别为{4,4,6,6,6,5}; 针对数组{2,3,4,2,6,2,5,1}的滑动窗口有以下6个:
+
{[2,3,4],2,6,2,5,1}, {2,[3,4,2],6,2,5,1}, {2,3,[4,2,6],2,5,1}, {2,3,4,[2,6,2],5,1},
{2,3,4,2,[6,2,5],1}, {2,3,4,2,6,[2,5,1]}。
这道题其实是昨天最后一道题JZ60
的升级版,其实也就是层次遍历二叉树(BFS)。层次遍历思想可以参见上一道题,只是此题需要结合二叉树的深度depth
进行解题。在每次需要打印的地方,当深度depth
对2取余,为0则从左到右打印,为1则反转打印。
解法思路:
+1 |
|
代码测试:
+1 |
|
题目描述:
+++一个整型数组里除了两个数字之外,其他的数字都出现了两次。请写程序找出这两个只出现一次的数字。
+
解法思路:
+ +1 |
|
代码测试:
+1 |
|
题目描述:
+++输入n个整数,找出其中最小的K个数。例如输入4,5,1,6,2,7,3,8这8个数字,则最小的4个数字是1,2,3,4。
+
解法思路:
这题第一印象是直接将列表从小到大进行排序然后返回前K个数即可。所以本题第一种方法就是利用快排然后返回前K个数得到结果,这个方法没什么好说的,只要对快排熟悉即可。
1 |
|
代码测试:
+1 |
|
题目描述:
+++数组中有一个数字出现的次数超过数组长度的一半,请找出这个数字。例如输入一个长度为9的数组{1,2,3,2,2,2,5,4,2}。
+
由于数字2在数组中出现了5次,超过数组长度的一半,因此输出2。如果不存在则输出0。
解法思路:
很朴素的做法,利用哈希进行统计出数字出现的次数,然后再与数组的长度的一半进行比较即可得到结果。
1 |
|
代码测试:
+1 |
|
题目描述:
+++HZ偶尔会拿些专业问题来忽悠那些非计算机专业的同学。今天测试组开完会后,他又发话了:在古老的一维模式识别中,常常需要计算连续子向量的最大和,
+
当向量全为正数的时候,问题很好解决。但是,如果向量中包含负数,是否应该包含某个负数,并期望旁边的正数会弥补它呢?
例如:{6,-3,-2,7,-15,1,2,2},连续子向量的最大和为8(从第0个开始,到第3个为止)。给一个数组,返回它的最大连续子序列的和,
你会不会被他忽悠住?(子向量的长度至少是1)
解法思路:
动态规划方法。
1 |
|
代码测试:
+1 |
|
题目描述:
+++在一个长度为n的数组里的所有数字都在0到n-1的范围内。 数组中某些数字是重复的,但不知道有几个数字是重复的。也不知道每个数字重复几次。
+
请找出数组中任意一个重复的数字。 例如,如果输入长度为7的数组{2,3,1,0,2,5,3},那么对应的输出是第一个重复的数字2。
解法思路:
+1 |
|
代码测试:
+1 |
|
由于近期来自客户需求,需要部门开发的AI平台支持上 PyTorch 框架的分布式训练,因此自己也是花了大概一周的时间,仔细研究了下 PyTorch 的分布式训练,中间也遇到了不少问题,好在通过查阅相关资料大都解决了,昨天也到客户那已经部署成功了。现将关于 PyTorch 分布式训练知识总结一下,方便大家或自己以后查阅,以下内容如有总结不到位的地方,请大家不吝赐教~
+Kubernetes 是一个可移植的、可扩展的开源平台,用于管理容器化的工作负载和服务,可促进声明式配置和自动化。Kubernetes 拥有一个庞大且快速增长的生态系统。Kubernetes 是 Google 于 2014 年 6 月基于其内部使用的 Borg 系统开源出来的容器编排调度引擎,Google 将其作为初始和核心项目贡献给 CNCF(云原生计算基金会),近年来逐渐发展出了云原生生态。
+Kubernetes 的目标不仅仅是一个编排系统,而是提供一个规范用以描述集群的架构,定义服务的最终状态,使系统自动地达到和维持该状态。Kubernetes 作为云原生应用的基石,相当于一个云操作系统,其重要性不言而喻。
+ + +容器是打包和运行应用程序的好方式。在生产环境中,您需要管理运行应用程序的容器,并确保不会停机。例如,如果一个容器发生故障,则需要启动另一个容器。如果系统处理此行为,会不会更容易?
+这就是 Kubernetes 的救援方法!Kubernetes 为您提供了一个可弹性运行分布式系统的框架。Kubernetes 会满足您的扩展要求、故障转移、部署模式等。例如,Kubernetes 可以轻松管理系统的 Canary 部署。
+Kubernetes 能够提供以下一些功能:
+因此综上,我们需要好好学习 Kubernetes 这个强大的云操作系统,增强自身的竞争力。工欲善其事,必先利其器,本篇也是 Kubernetes 系列的第一篇博文,讲述如何利用 Kubeadm 这个工具来搭建一套供自己学习的 Kubernetes 集群。
+Kubeadm 能够用以创建一个符合最佳实践的最小化 Kubernetes 集群。事实上,你可以使用 kubeadm 配置一个通过 Kubernetes 一致性测试的集群。 kubeadm 还支持其他集群生命周期功能, 例如:启动引导令牌和集群升级。
+kubeadm 工具很棒,如果你需要:
+你可以在各种机器上安装和使用 kubeadm:笔记本电脑, 一组云服务器,Raspberry Pi 等。无论是部署到云还是本地,你都可以将 kubeadm 集成到预配置系统中,例如 Ansible 或 Terraform。
+上述介绍过 kubeadm 的基础用法,接下来我将会介绍基于 Centos 8 安装 Kubernetes 组件以及 Docker。
+docker
1 |
|
kubernetes
1 |
|
1 |
|
1 |
|
这里安装了 Docker 公司发布的最新的 Docker CE(社区版),Kubernetes 相关的组件安装的 1.18.0 版本,基本是目前为止最新的版本了。
+利用 kubeadm 可以很简单的来初始化 kubernetes 集群的 master 节点,执行以下命令:
+1 |
|
上述命令行参数解释:
+--apiserver-advertise-address
:可用于为控制平面节点的 API server 设置广播地址,在 Kubernetes 项目“一切皆容器”的设计理念指导下,部署网络插件也是通过启动pod
的形式来配置网络,其中有两种网络插件可供部署:
1 |
|
1 |
|
1 |
|
可以看到,所有的系统 Pod 都成功启动了,而刚刚部署的 calico 网络插件则在 kube-system 下面新建了一个名叫 calico-kube-controllers-65f8bc95db-ngv7v 的 Pod,一般来说,这些 Pod 就是容器网络插件在每个节点上的控制组件。
+Kubernetes 支持容器网络插件,使用的是一个名叫 CNI 的通用接口,它也是当前容器网络的事实标准,市面上的所有容器网络开源项目都可以通过 CNI 接入 Kubernetes,比如 Flannel、Calico、Canal、Romana 等等,它们的部署方式也都是类似的“一键部署”。关于这些开源项目的实现细节和差异,后续会有相关的博文进行详细讲解。
+至此,Kubernetes 的 Master 节点就部署完成了。如果你只需要一个单节点的 Kubernetes,现在你就可以使用了。不过,在默认情况下,Kubernetes 的 Master 节点是不能运行用户 Pod 的,所以还需要额外做一个小操作。在本篇的最后部分,我会介绍到它。
+Kubernetes 的 计算节点跟 Master 节点几乎是相同的,它们运行着的都是一个 kubelet 组件。唯一的区别在于,在 kubeadm init 的过程中,kubelet 启动后,Master 节点上还会自动运行 kube-apiserver、kube-scheduler、kube-controller-manger 这三个系统 Pod。
执行以下命令:
1 |
|
用以加入192.168.56.12
这个 IP 的计算节点到集群中,以上Token
可用kubeclt token list
得到。
通过执行以上步骤便可以搭建好一个网络完整的 Kubernetes 集群。当然,也可以继续往集群中添加其他的插件,比如部署 Dashboard 可视化插件,部署容器存储插件等等。这个就因人而异了,留给大家自由发挥了…
+1 |
|
pod
资源1 |
|
Kubernetes 集群分为两个部分:
+其中控制平面的组件有:
+运行容器任务依赖于每个工作节点上运行的组件,包括:
+一直以来自己是不喜欢将一些总结放到博客里来的,感觉这个还是挺私密的,是自己一年的发展回顾。但是看了很多大佬的博客,他们都很擅于总结自己的一年,并且也会将之发到自己的博客上,我感觉这样也挺好的。自己之前都是将这些总结放到本地存储,但这样有时写了一会就不想去写了,很容易虎头蛇尾。因此我决定以后可以将一些总结,感触什么的放到博客里,以此来监督自己一直坚持下去~
+ + +2020,一个不平凡的一年,这整年人人都基本是带着口罩过来的,直到现在还是无法摆脱带口罩,每天出行仍需带着上地铁,进公司。在年初,因为疫情影响,相信很多人都是被困在家远程办公。刚开始在家办公,自己还是不适应的,没有公司的那种开发氛围,很多需求也不能面对面及时的沟通得以解决,这样还是挺不方便的。但是后来,随着在家办公的时间长了,感觉在家办公也不错,至少节省了上下班通勤路上的时间,每天从床上爬起来就可以投入工作,这种感觉还是挺好的。当然这样对于大多数人工作效率肯定是很低的,所以公司还是会尽量要求员工在家隔离完就需要回公司办公了,因此自己大概在今年3月份回到联想大厦办公了。
+其实自己在年初的时候给自己的2020定了一些计划的,但是关于实现与否,还真是偏差甚远。首先是打算这一年换一份工作的,最好是NLP算法工程师相关的工作。在今年的前三个月里,自己还是很认真的在学习NLP相关的知识,但是后面发现自己还是很难去找这相关的工作,加上后面在联想又大部分时间在做开发相关的工作,所以后面也就没再学习了。关于跳槽,从今年8月份开始更新几个网站的简历,然后也是8月份开始陆续接到了很多猎头的电话,也面试了很多了公司,最终拿了几个offer,待遇什么的较联想这边也有一定的涨幅。最后选择了一家互联网+金融的公司,信也科技,但不是算法相关的岗位,不过也挺符合自己的发展方向的,目前主要是机器学习容器云平台开发,主要是
Python / Go 作为技术栈, 基于 Kubernetes / Docker 打造基于云原生上传数据集,标注,特征提取,训练以及模型部署一体化的机器学习平台。
kube-apiserver
是 Kubernetes
最重要的核心组件之一,主要能提供的功能如下:
RESTful API
的形式提供其他组件查询,修改集群状态的 CURD(Create,Read,Update,Detele)
接口,然后将状态储存到 etcd
中;kube-apiserver
提供了 Kubernetes
的 REST API
,实现了认证、授权、准入控制等安全校验功能,同时也负责集群状态的存储操作(通过 etcd
)。
kube-apiserver
提供了为每种语言提供了 SDK
,方便用户访问集群其他组件,以及将数据存储或更新到etcd
中,如下:
Client
.查询 kube-apiserver
支持API
的版本
1 |
|
查询 kube-apiserver
支持API
的资源对象
1 |
|
查看 kube-apiserver
的 v1/namepsace
信息
1 |
|
通过启动 proxy
获取集群配置信息
1 |
|
查看集群各组件信息
+1 |
|
在 pod 里面访问
+1 |
|
在 master 节点上访问
+1 |
|
今天在使用 golang 重构 python 站点时,遇到了一个有趣的事情。就是在 python 函数中参数是可以设置默认值的,这样在函数调用时,就不需要每个参数都传一个值,其实这也是变相的实现重载功能。但是我发现在 golang 中参数是不能设置默认值的,但是基于程序员的直觉,相信此事没那么简单,于是抱着打破沙锅问到底的态度,就有了这篇文章。
+首先,通过一个例子,说明我在编码过程中遇到的问题。对于平台后端开发工程师来说,会经常遇到以下场景:
通过
基于此,我将这些查询方式抽象成一个方法,之后所有的功能模块,都可以使用该方法进行多条件联合查询数据记录,具体抽象如下:
+1 |
|
Welcome to Hexo! This is your very first post. Check documentation for more info. If you get any problems when using Hexo, you can find the answer in troubleshooting or you can ask me on GitHub.
+1 |
|
More info: Writing
+1 |
|
More info: Server
+1 |
|
More info: Generating
+1 |
|
More info: Deployment
+ + +共计 29 篇文章
+2020
+ + + +共计 29 篇文章
+2020
+ + + +共计 29 篇文章
+2020
+ + + +共计 29 篇文章
+2020
+ + + +共计 29 篇文章
+2020
+ + + +共计 29 篇文章
+2020
+ + + +共计 29 篇文章
+2020
+ + + +共计 29 篇文章
+2020
+ + + +共计 29 篇文章
+2020
+ + + +共计 29 篇文章
+2021
+ + + +共计 29 篇文章
+2021
+ + + +共计 29 篇文章
+2024
+ + + +2023
+ + + +2021
+ + + +2020
+ + + +共计 29 篇文章
+2020
+ + + +共计 29 篇文章
+2020
+ + + +1 |
|
More info: Writing
1 |
|
More info: Server
1 |
|
More info: Generating
1 |
|
More info: Deployment
]]>今天在使用 golang 重构 python 站点时,遇到了一个有趣的事情。就是在 python 函数中参数是可以设置默认值的,这样在函数调用时,就不需要每个参数都传一个值,其实这也是变相的实现重载功能。但是我发现在 golang 中参数是不能设置默认值的,但是基于程序员的直觉,相信此事没那么简单,于是抱着打破沙锅问到底的态度,就有了这篇文章。
首先,通过一个例子,说明我在编码过程中遇到的问题。对于平台后端开发工程师来说,会经常遇到以下场景:
通过
基于此,我将这些查询方式抽象成一个方法,之后所有的功能模块,都可以使用该方法进行多条件联合查询数据记录,具体抽象如下:
1 |
|
kube-apiserver
是 Kubernetes
最重要的核心组件之一,主要能提供的功能如下:RESTful API
的形式提供其他组件查询,修改集群状态的 CURD(Create,Read,Update,Detele)
接口,然后将状态储存到 etcd
中;kube-apiserver
提供了 Kubernetes
的 REST API
,实现了认证、授权、准入控制等安全校验功能,同时也负责集群状态的存储操作(通过 etcd
)。
kube-apiserver
提供了为每种语言提供了 SDK
,方便用户访问集群其他组件,以及将数据存储或更新到etcd
中,如下:
Client
.查询 kube-apiserver
支持API
的版本
1 |
|
查询 kube-apiserver
支持API
的资源对象
1 |
|
查看 kube-apiserver
的 v1/namepsace
信息
1 |
|
通过启动 proxy
获取集群配置信息
1 |
|
查看集群各组件信息
1 |
|
在 pod 里面访问
1 |
|
在 master 节点上访问
1 |
|
2020,一个不平凡的一年,这整年人人都基本是带着口罩过来的,直到现在还是无法摆脱带口罩,每天出行仍需带着上地铁,进公司。在年初,因为疫情影响,相信很多人都是被困在家远程办公。刚开始在家办公,自己还是不适应的,没有公司的那种开发氛围,很多需求也不能面对面及时的沟通得以解决,这样还是挺不方便的。但是后来,随着在家办公的时间长了,感觉在家办公也不错,至少节省了上下班通勤路上的时间,每天从床上爬起来就可以投入工作,这种感觉还是挺好的。当然这样对于大多数人工作效率肯定是很低的,所以公司还是会尽量要求员工在家隔离完就需要回公司办公了,因此自己大概在今年3月份回到联想大厦办公了。
其实自己在年初的时候给自己的2020定了一些计划的,但是关于实现与否,还真是偏差甚远。首先是打算这一年换一份工作的,最好是NLP算法工程师相关的工作。在今年的前三个月里,自己还是很认真的在学习NLP相关的知识,但是后面发现自己还是很难去找这相关的工作,加上后面在联想又大部分时间在做开发相关的工作,所以后面也就没再学习了。关于跳槽,从今年8月份开始更新几个网站的简历,然后也是8月份开始陆续接到了很多猎头的电话,也面试了很多了公司,最终拿了几个offer,待遇什么的较联想这边也有一定的涨幅。最后选择了一家互联网+金融的公司,信也科技,但不是算法相关的岗位,不过也挺符合自己的发展方向的,目前主要是机器学习容器云平台开发,主要是
Python / Go 作为技术栈, 基于 Kubernetes / Docker 打造基于云原生上传数据集,标注,特征提取,训练以及模型部署一体化的机器学习平台。
Kubernetes 集群分为两个部分:
其中控制平面的组件有:
运行容器任务依赖于每个工作节点上运行的组件,包括:
1 |
|
代码测试:
1 |
|
题目描述:
请实现一个函数按照之字形打印二叉树,即第一行按照从左到右的顺序打印,第二层按照从右至左的顺序打印,第三行按照从左到右的顺序打印,其他行以此类推。
解法思路:
这道题其实是昨天最后一道题JZ60
的升级版,其实也就是层次遍历二叉树(BFS)。层次遍历思想可以参见上一道题,只是此题需要结合二叉树的深度depth
进行解题。在每次需要打印的地方,当深度depth
对2取余,为0则从左到右打印,为1则反转打印。
1 |
|
代码测试:
1 |
|
题目描述:
请实现一个函数,用来判断一棵二叉树是不是对称的。注意,如果一个二叉树同此二叉树的镜像是同样的,定义其为对称的。
解法思路:
1 |
|
代码测试:
1 |
|
题目描述:
给定一个二叉树和其中的一个结点,请找出中序遍历顺序的下一个结点并且返回。注意,树中的结点不仅包含左右子结点,同时包含指向父结点的指针。
解法思路:
1 |
|
代码测试:
1 |
|
题目描述:
输入一棵二叉树,判断该二叉树是否是平衡二叉树。
在这里,我们只需要考虑其平衡性,不需要考虑其是不是排序二叉树
解法思路:
1 |
|
代码测试:
1 |
|
题目描述:
输入一个矩阵,按照从外向里以顺时针的顺序依次打印出每一个数字,例如,如果输入如下4 X 4矩阵: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 则依次打印出数字1,2,3,4,8,12,16,15,14,13,9,5,6,7,11,10.
解法思路:
这道题刚开始自己一看,就是想着设置一些索引位置,按照索引位置打印来打印不就行了。后来再认真读题,发现它输入的二维矩阵大小是变化的,不是固定大小,才发现自己的想法太native
。
看了下讨论区,发现只是需要确定几个固定位置的索引值,便可以不管输入矩阵的大小,自适应的便能够确定顺时针打印每个位置的索引,然后再根据这个索引来打印矩阵就行,还真是巧妙。其实在确定好几个顶点的位置,也就相当于确定了方向,然后不管是顺时针还是逆时针,下次都可以方便的解题了。
1 |
|
代码测试:
1 |
|
题目描述:
输入一棵二叉树,求该树的深度。从根结点到叶结点依次经过的结点(含根、叶结点)形成树的一条路径,最长路径的长度为树的深度。
解法思路:
1 |
|
代码测试:
1 |
|
题目描述:
从上到下按层打印二叉树,同一层结点从左至右输出。每一层输出一行。
解法思路:
1 |
|
代码测试:
1 |
|
题目描述:
把一个数组最开始的若干个元素搬到数组的末尾,我们称之为数组的旋转。
输入一个非递减排序的数组的一个旋转,输出旋转数组的最小元素。
例如数组{3,4,5,1,2}为{1,2,3,4,5}的一个旋转,该数组的最小值为1。
NOTE:给出的所有元素都大于0,若数组大小为0,请返回0。
解法思路:
这题主要是考察二分查找。二分查找,又叫折半查找。它的前提是线性表中的数据必须是有序的,线性表必须采用顺序存储。主要思想是:在有序表中,去中间记录作为比较对象,若给定值与中间记录的关键字相等,则查找成功;若给定值小于中间记录的关键字,则在中间记录的左半区继续查找;若给定值大于中间记录的关键字,则在中间记录的右半区继续查找;不断重复上述过程,直至查找成功,或所有查找区域无记录,查找失败为止。
上面介绍了二分查找的主要思路,而本题难点在于找到中间值与谁进行比较? 再认真审下题,给定的是非递减排序的数组,也就是“平序”或升序。例如:[1, 2, 3, 3, 3, 5, 6]
(“平序”),[1, 2, 3, 4, 5, 6]
(升序)。然后再做旋转得到旋转数组[3, 3, 5, 6, 1, 2, 3]
,[4, 5, 6, 1, 2, 3]
,可以确定的是旋转后的数组nums[0] >= nums[-1]
恒成立。
这样也就得到了nums[mid]
与哪个值进行比较了,当然是:
nums[mid] > nums[left]
, 这个时候 left = mid + 1
nums[mid] < nums[right]
, 这个时候 right = mid
nums[mid] = nums[right]
, 这个时候 left += 1
这里可以一定意义上认为nums[left]
与nums[right]
近似相等,这样便于理解。
注: 以上
nums
代表传入的旋转数组,left
指数组的第一个数,right
指数组末尾的数,mid
指数组中间位置的数。
1 |
|
代码测试:
1 |
|
题目描述:
操作给定的二叉树,将其变换为源二叉树的镜像。
二叉树的镜像定义如下:
源二叉树 8 / \ 6 10 / \ / \5 7 9 11镜像二叉树 8 / \ 10 6 / \ / \11 9 7 5
解法思路:
1 |
|
代码测试:
1 |
|
题目描述:
输入一个整数数组,判断该数组是不是某二叉搜索树的后序遍历的结果。如果是则输出Yes,否则输出No。假设输入的数组的任意两个数字都互不相同。
解法思路:
1 |
|
代码测试:
1 |
|
题目描述:
给你一根长度为n的绳子,请把绳子剪成整数长的m段(m、n都是整数,n>1并且m>1,m<=n),每段绳子的长度记为 k[1],…,k[m]。请问 k[1]x…xk[m] 可能的最大乘积是多少?例如,当绳子的长度是8时,我们把它剪成长度分别为2、3、3的三段,此时得到的最大乘积是18。
输入:8
输出:18
解法思路:
代码测试:
]]>共计 2 篇文章
+2020
+ + + +共计 2 篇文章
+2020
+ + + +共计 3 篇文章
+2023
+ + + +2020
+ + + +共计 4 篇文章
+2021
+ + + +2020
+ + + +共计 12 篇文章
+2020
+ + + +' + match_content + '...
'; + } + } + }); + if (resultHTML.indexOf('list-group-item') === -1) { + return $input.addClass('invalid').removeClass('valid'); + } + $input.addClass('valid').removeClass('invalid'); + $result.html(resultHTML); + }); + } + }); + } + + function localSearchReset(searchSelector, resultSelector) { + 'use strict'; + var $input = jQuery(searchSelector); + var $result = jQuery(resultSelector); + + if ($input.length === 0) { + // eslint-disable-next-line no-console + throw Error('No element selected by the searchSelector'); + } + if ($result.length === 0) { + // eslint-disable-next-line no-console + throw Error('No element selected by the resultSelector'); + } + + $input.val('').removeClass('invalid').removeClass('valid'); + $result.html(''); + } + + var modal = jQuery('#modalSearch'); + var searchSelector = '#local-search-input'; + var resultSelector = '#local-search-result'; + modal.on('show.bs.modal', function() { + var path = CONFIG.search_path || '/local-search.xml'; + localSearchFunc(path, searchSelector, resultSelector); + }); + modal.on('shown.bs.modal', function() { + jQuery('#local-search-input').focus(); + }); + modal.on('hidden.bs.modal', function() { + localSearchReset(searchSelector, resultSelector); + }); +})(); diff --git a/js/plugins.js b/js/plugins.js new file mode 100644 index 0000000..0ce1074 --- /dev/null +++ b/js/plugins.js @@ -0,0 +1,164 @@ +/* global Fluid, CONFIG */ + +HTMLElement.prototype.wrap = function(wrapper) { + this.parentNode.insertBefore(wrapper, this); + this.parentNode.removeChild(this); + wrapper.appendChild(this); +}; + +Fluid.plugins = { + + typing: function(text) { + if (!('Typed' in window)) { return; } + + var typed = new window.Typed('#subtitle', { + strings: [ + ' ', + text + ' ' + ], + cursorChar: CONFIG.typing.cursorChar, + typeSpeed : CONFIG.typing.typeSpeed, + loop : CONFIG.typing.loop + }); + typed.stop(); + var subtitle = document.getElementById('subtitle'); + if (subtitle) { + subtitle.innerText = ''; + } + jQuery(document).ready(function() { + typed.start(); + }); + }, + + fancyBox: function(selector) { + if (!CONFIG.image_zoom.enable || !('fancybox' in jQuery)) { return; } + + jQuery(selector || '.markdown-body :not(a) > img, .markdown-body > img').each(function() { + var $image = jQuery(this); + var imageUrl = $image.attr('data-src') || $image.attr('src') || ''; + if (CONFIG.image_zoom.img_url_replace) { + var rep = CONFIG.image_zoom.img_url_replace; + var r1 = rep[0] || ''; + var r2 = rep[1] || ''; + if (r1) { + if (/^re:/.test(r1)) { + r1 = r1.replace(/^re:/, ''); + var reg = new RegExp(r1, 'gi'); + imageUrl = imageUrl.replace(reg, r2); + } else { + imageUrl = imageUrl.replace(r1, r2); + } + } + } + var $imageWrap = $image.wrap(` + ` + ).parent('a'); + if ($imageWrap.length !== 0) { + if ($image.is('.group-image-container img')) { + $imageWrap.attr('data-fancybox', 'group').attr('rel', 'group'); + } else { + $imageWrap.attr('data-fancybox', 'default').attr('rel', 'default'); + } + + var imageTitle = $image.attr('title') || $image.attr('alt'); + if (imageTitle) { + $imageWrap.attr('title', imageTitle).attr('data-caption', imageTitle); + } + } + }); + + jQuery.fancybox.defaults.hash = false; + jQuery('.fancybox').fancybox({ + loop : true, + helpers: { + overlay: { + locked: false + } + } + }); + }, + + imageCaption: function(selector) { + if (!CONFIG.image_caption.enable) { return; } + + jQuery(selector || `.markdown-body > p > img, .markdown-body > figure > img, + .markdown-body > p > a.fancybox, .markdown-body > figure > a.fancybox`).each(function() { + var $target = jQuery(this); + var $figcaption = $target.next('figcaption'); + if ($figcaption.length !== 0) { + $figcaption.addClass('image-caption'); + } else { + var imageTitle = $target.attr('title') || $target.attr('alt'); + if (imageTitle) { + $target.after(` `); + } + } + }); + }, + + codeWidget() { + var enableLang = CONFIG.code_language.enable && CONFIG.code_language.default; + var enableCopy = CONFIG.copy_btn && 'ClipboardJS' in window; + if (!enableLang && !enableCopy) { + return; + } + + function getBgClass(ele) { + return Fluid.utils.getBackgroundLightness(ele) >= 0 ? 'code-widget-light' : 'code-widget-dark'; + } + + var copyTmpl = ''; + copyTmpl += ' '; + jQuery('.markdown-body pre').each(function() { + var $pre = jQuery(this); + if ($pre.find('code.mermaid').length > 0) { + return; + } + if ($pre.find('span.line').length > 0) { + return; + } + + var lang = ''; + + if (enableLang) { + lang = CONFIG.code_language.default; + if ($pre[0].children.length > 0 && $pre[0].children[0].classList.length >= 2 && $pre.children().hasClass('hljs')) { + lang = $pre[0].children[0].classList[1]; + } else if ($pre[0].getAttribute('data-language')) { + lang = $pre[0].getAttribute('data-language'); + } else if ($pre.parent().hasClass('sourceCode') && $pre[0].children.length > 0 && $pre[0].children[0].classList.length >= 2) { + lang = $pre[0].children[0].classList[1]; + $pre.parent().addClass('code-wrapper'); + } else if ($pre.parent().hasClass('markdown-body') && $pre[0].classList.length === 0) { + $pre.wrap(''); + } + lang = lang.toUpperCase().replace('NONE', CONFIG.code_language.default); + } + $pre.append(copyTmpl.replace('LANG', lang).replace('code-widget">', + getBgClass($pre[0]) + (enableCopy ? ' code-widget copy-btn" data-clipboard-snippet>' : ' code-widget">'))); + + if (enableCopy) { + var clipboard = new ClipboardJS('.copy-btn', { + target: function(trigger) { + var nodes = trigger.parentNode.childNodes; + for (var i = 0; i < nodes.length; i++) { + if (nodes[i].tagName === 'CODE') { + return nodes[i]; + } + } + } + }); + clipboard.on('success', function(e) { + e.clearSelection(); + e.trigger.innerHTML = e.trigger.innerHTML.replace('icon-copy', 'icon-success'); + setTimeout(function() { + e.trigger.innerHTML = e.trigger.innerHTML.replace('icon-success', 'icon-copy'); + }, 2000); + }); + } + }); + } +}; diff --git a/js/utils.js b/js/utils.js new file mode 100644 index 0000000..8ca6140 --- /dev/null +++ b/js/utils.js @@ -0,0 +1,231 @@ +/* global Fluid, CONFIG */ + +window.requestAnimationFrame = window.requestAnimationFrame || window.webkitRequestAnimationFrame || window.mozRequestAnimationFrame; + +Fluid.utils = { + + listenScroll: function(callback) { + var dbc = new Debouncer(callback); + window.addEventListener('scroll', dbc, false); + dbc.handleEvent(); + return dbc; + }, + + unlistenScroll: function(callback) { + window.removeEventListener('scroll', callback); + }, + + scrollToElement: function(target, offset) { + var of = jQuery(target).offset(); + if (of) { + jQuery('html,body').animate({ + scrollTop: of.top + (offset || 0), + easing : 'swing' + }); + } + }, + + elementVisible: function(element, offsetFactor) { + offsetFactor = offsetFactor && offsetFactor >= 0 ? offsetFactor : 0; + var rect = element.getBoundingClientRect(); + var height = window.innerHeight || document.documentElement.clientHeight; + var top = rect.top; + return (top >= 0 && top <= height * (offsetFactor + 1)) + || (top <= 0 && top >= -(height * offsetFactor) - rect.height); + }, + + waitElementVisible: function(selectorOrElement, callback, offsetFactor) { + var runningOnBrowser = typeof window !== 'undefined'; + var isBot = (runningOnBrowser && !('onscroll' in window)) + || (typeof navigator !== 'undefined' && /(gle|ing|ro|msn)bot|crawl|spider|yand|duckgo/i.test(navigator.userAgent)); + if (!runningOnBrowser || isBot) { + return; + } + + offsetFactor = offsetFactor && offsetFactor >= 0 ? offsetFactor : 0; + + function waitInViewport(element) { + if (Fluid.utils.elementVisible(element, offsetFactor)) { + callback(); + return; + } + if ('IntersectionObserver' in window) { + var io = new IntersectionObserver(function(entries, ob) { + if (entries[0].isIntersecting) { + callback(); + ob.disconnect(); + } + }, { + threshold : [0], + rootMargin: (window.innerHeight || document.documentElement.clientHeight) * offsetFactor + 'px' + }); + io.observe(element); + } else { + var wrapper = Fluid.utils.listenScroll(function() { + if (Fluid.utils.elementVisible(element, offsetFactor)) { + Fluid.utils.unlistenScroll(wrapper); + callback(); + } + }); + } + } + + if (typeof selectorOrElement === 'string') { + this.waitElementLoaded(selectorOrElement, function(element) { + waitInViewport(element); + }); + } else { + waitInViewport(selectorOrElement); + } + }, + + waitElementLoaded: function(selector, callback) { + var runningOnBrowser = typeof window !== 'undefined'; + var isBot = (runningOnBrowser && !('onscroll' in window)) + || (typeof navigator !== 'undefined' && /(gle|ing|ro|msn)bot|crawl|spider|yand|duckgo/i.test(navigator.userAgent)); + if (!runningOnBrowser || isBot) { + return; + } + + if ('MutationObserver' in window) { + var mo = new MutationObserver(function(records, ob) { + var ele = document.querySelector(selector); + if (ele) { + callback(ele); + ob.disconnect(); + } + }); + mo.observe(document, { childList: true, subtree: true }); + } else { + document.addEventListener('DOMContentLoaded', function() { + var waitLoop = function() { + var ele = document.querySelector(selector); + if (ele) { + callback(ele); + } else { + setTimeout(waitLoop, 100); + } + }; + waitLoop(); + }); + } + }, + + createScript: function(url, onload) { + var s = document.createElement('script'); + s.setAttribute('src', url); + s.setAttribute('type', 'text/javascript'); + s.setAttribute('charset', 'UTF-8'); + s.async = false; + if (typeof onload === 'function') { + if (window.attachEvent) { + s.onreadystatechange = function() { + var e = s.readyState; + if (e === 'loaded' || e === 'complete') { + s.onreadystatechange = null; + onload(); + } + }; + } else { + s.onload = onload; + } + } + var ss = document.getElementsByTagName('script'); + var e = ss.length > 0 ? ss[ss.length - 1] : document.head || document.documentElement; + e.parentNode.insertBefore(s, e.nextSibling); + }, + + createCssLink: function(url) { + var l = document.createElement('link'); + l.setAttribute('rel', 'stylesheet'); + l.setAttribute('type', 'text/css'); + l.setAttribute('href', url); + var e = document.getElementsByTagName('link')[0] + || document.getElementsByTagName('head')[0] + || document.head || document.documentElement; + e.parentNode.insertBefore(l, e); + }, + + loadComments: function(selector, loadFunc) { + var ele = document.querySelector('#comments[lazyload]'); + if (ele) { + var callback = function() { + loadFunc(); + ele.removeAttribute('lazyload'); + }; + Fluid.utils.waitElementVisible(selector, callback, CONFIG.lazyload.offset_factor); + } else { + loadFunc(); + } + }, + + getBackgroundLightness(selectorOrElement) { + var ele = selectorOrElement; + if (typeof selectorOrElement === 'string') { + ele = document.querySelector(selectorOrElement); + } + var view = ele.ownerDocument.defaultView; + if (!view) { + view = window; + } + var rgbArr = view.getComputedStyle(ele).backgroundColor.replace(/rgba*\(/, '').replace(')', '').split(/,\s*/); + if (rgbArr.length < 3) { + return 0; + } + var colorCast = (0.213 * rgbArr[0]) + (0.715 * rgbArr[1]) + (0.072 * rgbArr[2]); + return colorCast === 0 || colorCast > 255 / 2 ? 1 : -1; + }, + + retry(handler, interval, times) { + if (times <= 0) { + return; + } + var next = function() { + if (--times >= 0 && !handler()) { + setTimeout(next, interval); + } + }; + setTimeout(next, interval); + }, + +}; + +/** + * Handles debouncing of events via requestAnimationFrame + * @see http://www.html5rocks.com/en/tutorials/speed/animations/ + * @param {Function} callback The callback to handle whichever event + */ +function Debouncer(callback) { + this.callback = callback; + this.ticking = false; +} +Debouncer.prototype = { + constructor: Debouncer, + + /** + * dispatches the event to the supplied callback + * @private + */ + update: function() { + this.callback && this.callback(); + this.ticking = false; + }, + + /** + * ensures events don't get stacked + * @private + */ + requestTick: function() { + if (!this.ticking) { + requestAnimationFrame(this.rafCallback || (this.rafCallback = this.update.bind(this))); + this.ticking = true; + } + }, + + /** + * Attach this as the event listeners + */ + handleEvent: function() { + this.requestTick(); + } +}; diff --git a/links/index.html b/links/index.html new file mode 100644 index 0000000..4c21819 --- /dev/null +++ b/links/index.html @@ -0,0 +1,480 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +1 |
|
More info: Writing
1 |
|
More info: Server
1 |
|
More info: Generating
1 |
|
More info: Deployment
]]>今天在使用 golang 重构 python 站点时,遇到了一个有趣的事情。就是在 python 函数中参数是可以设置默认值的,这样在函数调用时,就不需要每个参数都传一个值,其实这也是变相的实现重载功能。但是我发现在 golang 中参数是不能设置默认值的,但是基于程序员的直觉,相信此事没那么简单,于是抱着打破沙锅问到底的态度,就有了这篇文章。
首先,通过一个例子,说明我在编码过程中遇到的问题。对于平台后端开发工程师来说,会经常遇到以下场景:
通过
基于此,我将这些查询方式抽象成一个方法,之后所有的功能模块,都可以使用该方法进行多条件联合查询数据记录,具体抽象如下:
1 |
|
kube-apiserver
是 Kubernetes
最重要的核心组件之一,主要能提供的功能如下:RESTful API
的形式提供其他组件查询,修改集群状态的 CURD(Create,Read,Update,Detele)
接口,然后将状态储存到 etcd
中;kube-apiserver
提供了 Kubernetes
的 REST API
,实现了认证、授权、准入控制等安全校验功能,同时也负责集群状态的存储操作(通过 etcd
)。
kube-apiserver
提供了为每种语言提供了 SDK
,方便用户访问集群其他组件,以及将数据存储或更新到etcd
中,如下:
Client
.查询 kube-apiserver
支持API
的版本
1 |
|
查询 kube-apiserver
支持API
的资源对象
1 |
|
查看 kube-apiserver
的 v1/namepsace
信息
1 |
|
通过启动 proxy
获取集群配置信息
1 |
|
查看集群各组件信息
1 |
|
在 pod 里面访问
1 |
|
在 master 节点上访问
1 |
|
2020,一个不平凡的一年,这整年人人都基本是带着口罩过来的,直到现在还是无法摆脱带口罩,每天出行仍需带着上地铁,进公司。在年初,因为疫情影响,相信很多人都是被困在家远程办公。刚开始在家办公,自己还是不适应的,没有公司的那种开发氛围,很多需求也不能面对面及时的沟通得以解决,这样还是挺不方便的。但是后来,随着在家办公的时间长了,感觉在家办公也不错,至少节省了上下班通勤路上的时间,每天从床上爬起来就可以投入工作,这种感觉还是挺好的。当然这样对于大多数人工作效率肯定是很低的,所以公司还是会尽量要求员工在家隔离完就需要回公司办公了,因此自己大概在今年3月份回到联想大厦办公了。
其实自己在年初的时候给自己的2020定了一些计划的,但是关于实现与否,还真是偏差甚远。首先是打算这一年换一份工作的,最好是NLP算法工程师相关的工作。在今年的前三个月里,自己还是很认真的在学习NLP相关的知识,但是后面发现自己还是很难去找这相关的工作,加上后面在联想又大部分时间在做开发相关的工作,所以后面也就没再学习了。关于跳槽,从今年8月份开始更新几个网站的简历,然后也是8月份开始陆续接到了很多猎头的电话,也面试了很多了公司,最终拿了几个offer,待遇什么的较联想这边也有一定的涨幅。最后选择了一家互联网+金融的公司,信也科技,但不是算法相关的岗位,不过也挺符合自己的发展方向的,目前主要是机器学习容器云平台开发,主要是
Python / Go 作为技术栈, 基于 Kubernetes / Docker 打造基于云原生上传数据集,标注,特征提取,训练以及模型部署一体化的机器学习平台。
Kubernetes 集群分为两个部分:
其中控制平面的组件有:
运行容器任务依赖于每个工作节点上运行的组件,包括:
1 |
|
代码测试:
1 |
|
题目描述:
请实现一个函数按照之字形打印二叉树,即第一行按照从左到右的顺序打印,第二层按照从右至左的顺序打印,第三行按照从左到右的顺序打印,其他行以此类推。
解法思路:
这道题其实是昨天最后一道题JZ60
的升级版,其实也就是层次遍历二叉树(BFS)。层次遍历思想可以参见上一道题,只是此题需要结合二叉树的深度depth
进行解题。在每次需要打印的地方,当深度depth
对2取余,为0则从左到右打印,为1则反转打印。
1 |
|
代码测试:
1 |
|
题目描述:
请实现一个函数,用来判断一棵二叉树是不是对称的。注意,如果一个二叉树同此二叉树的镜像是同样的,定义其为对称的。
解法思路:
1 |
|
代码测试:
1 |
|
题目描述:
给定一个二叉树和其中的一个结点,请找出中序遍历顺序的下一个结点并且返回。注意,树中的结点不仅包含左右子结点,同时包含指向父结点的指针。
解法思路:
1 |
|
代码测试:
1 |
|
题目描述:
输入一棵二叉树,判断该二叉树是否是平衡二叉树。
在这里,我们只需要考虑其平衡性,不需要考虑其是不是排序二叉树
解法思路:
1 |
|
代码测试:
1 |
|
题目描述:
输入一个矩阵,按照从外向里以顺时针的顺序依次打印出每一个数字,例如,如果输入如下4 X 4矩阵: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 则依次打印出数字1,2,3,4,8,12,16,15,14,13,9,5,6,7,11,10.
解法思路:
这道题刚开始自己一看,就是想着设置一些索引位置,按照索引位置打印来打印不就行了。后来再认真读题,发现它输入的二维矩阵大小是变化的,不是固定大小,才发现自己的想法太native
。
看了下讨论区,发现只是需要确定几个固定位置的索引值,便可以不管输入矩阵的大小,自适应的便能够确定顺时针打印每个位置的索引,然后再根据这个索引来打印矩阵就行,还真是巧妙。其实在确定好几个顶点的位置,也就相当于确定了方向,然后不管是顺时针还是逆时针,下次都可以方便的解题了。
1 |
|
代码测试:
1 |
|
题目描述:
输入一棵二叉树,求该树的深度。从根结点到叶结点依次经过的结点(含根、叶结点)形成树的一条路径,最长路径的长度为树的深度。
解法思路:
1 |
|
代码测试:
1 |
|
题目描述:
从上到下按层打印二叉树,同一层结点从左至右输出。每一层输出一行。
解法思路:
1 |
|
代码测试:
1 |
|
题目描述:
把一个数组最开始的若干个元素搬到数组的末尾,我们称之为数组的旋转。
输入一个非递减排序的数组的一个旋转,输出旋转数组的最小元素。
例如数组{3,4,5,1,2}为{1,2,3,4,5}的一个旋转,该数组的最小值为1。
NOTE:给出的所有元素都大于0,若数组大小为0,请返回0。
解法思路:
这题主要是考察二分查找。二分查找,又叫折半查找。它的前提是线性表中的数据必须是有序的,线性表必须采用顺序存储。主要思想是:在有序表中,去中间记录作为比较对象,若给定值与中间记录的关键字相等,则查找成功;若给定值小于中间记录的关键字,则在中间记录的左半区继续查找;若给定值大于中间记录的关键字,则在中间记录的右半区继续查找;不断重复上述过程,直至查找成功,或所有查找区域无记录,查找失败为止。
上面介绍了二分查找的主要思路,而本题难点在于找到中间值与谁进行比较? 再认真审下题,给定的是非递减排序的数组,也就是“平序”或升序。例如:[1, 2, 3, 3, 3, 5, 6]
(“平序”),[1, 2, 3, 4, 5, 6]
(升序)。然后再做旋转得到旋转数组[3, 3, 5, 6, 1, 2, 3]
,[4, 5, 6, 1, 2, 3]
,可以确定的是旋转后的数组nums[0] >= nums[-1]
恒成立。
这样也就得到了nums[mid]
与哪个值进行比较了,当然是:
nums[mid] > nums[left]
, 这个时候 left = mid + 1
nums[mid] < nums[right]
, 这个时候 right = mid
nums[mid] = nums[right]
, 这个时候 left += 1
这里可以一定意义上认为nums[left]
与nums[right]
近似相等,这样便于理解。
注: 以上
nums
代表传入的旋转数组,left
指数组的第一个数,right
指数组末尾的数,mid
指数组中间位置的数。
1 |
|
代码测试:
1 |
|
题目描述:
操作给定的二叉树,将其变换为源二叉树的镜像。
二叉树的镜像定义如下:
源二叉树 8 / \ 6 10 / \ / \5 7 9 11镜像二叉树 8 / \ 10 6 / \ / \11 9 7 5
解法思路:
1 |
|
代码测试:
1 |
|
题目描述:
输入一个整数数组,判断该数组是不是某二叉搜索树的后序遍历的结果。如果是则输出Yes,否则输出No。假设输入的数组的任意两个数字都互不相同。
解法思路:
1 |
|
代码测试:
1 |
|
题目描述:
给你一根长度为n的绳子,请把绳子剪成整数长的m段(m、n都是整数,n>1并且m>1,m<=n),每段绳子的长度记为 k[1],…,k[m]。请问 k[1]x…xk[m] 可能的最大乘积是多少?例如,当绳子的长度是8时,我们把它剪成长度分别为2、3、3的三段,此时得到的最大乘积是18。
输入:8
输出:18
解法思路:
代码测试:
]]>题目描述:
一只青蛙一次可以跳上1级台阶,也可以跳上2级。求该青蛙跳上一个n级的台阶总共有多少种跳法(先后次序不同算不同的结果)。
解法思路:
1 |
|
代码测试:
1 |
|
题目描述:
一只青蛙一次可以跳上1级台阶,也可以跳上2级……它也可以跳上n级。求该青蛙跳上一个n级的台阶总共有多少种跳法。
解法思路:
1 |
|
代码测试:
1 |
|
题目描述:
我们可以用21的小矩形横着或者竖着去覆盖更大的矩形。请问用n个21的小矩形无重叠地覆盖一个2*n的大矩形,总共有多少种方法?
解法思路:
1 |
|
代码测试:
1 |
|
题目描述:
输入两个整数序列,第一个序列表示栈的压入顺序,请判断第二个序列是否可能为该栈的弹出顺序。假设压入栈的所有数字均不相等。
例如序列1,2,3,4,5是某栈的压入顺序,序列4,5,3,2,1是该压栈序列对应的一个弹出序列,但4,3,5,1,2就不可能是该压栈序列的弹出序列。
(注意:这两个序列的长度是相等的)
解法思路:
1 |
|
代码测试:
]]>题目描述:
输入某二叉树的前序遍历和中序遍历的结果,请重建出该二叉树。假设输入的前序遍历和中序遍历的结果中都不含重复的数字。例如输入前序遍历序列 [1,2,4,7,3,5,6,8] 和中序遍历序列 [4,7,2,1,5,3,8,6] ,则重建二叉树并返回。
解法思路:
使用递归的方法求解。这道题需要对二叉树的性质比较了解,需要熟悉二叉树的几种遍历方式。
前序遍历是先遍历根节点,然后遍历左节点,最后遍历右节点(根左右)
中序遍历是先遍历左节点,然后遍历根节点,最后遍历右节点(左根右)
后序遍历是先遍历左节点,然后遍历右节点,最后遍历根节点(根左右)
本题给定前序遍历以及中序遍历的序列,可以知道前序遍历第一个值一定是根节点。而根节点在中序遍历中会把左右子树分成两半。因此本题的关键是找到根节点,然后将左右子树依次递归重建得到二叉树。
使用递归是需要结束条件的,当前序或中序遍历序列为None
时,便可推出递归,得到二叉树。
1 |
|
本题只需写好reConstructBinaryTree
这个方法,上面代码其他三个函数是用来前序、中序以及后序遍历重建得到二叉树的,以方便大家调试。
代码测试:
1 |
|
题目描述:
操作给定的二叉树,将其变换为源二叉树的镜像。
二叉树的镜像定义如下:
源二叉树 8 / \ 6 10 / \ / \5 7 9 11镜像二叉树 8 / \ 10 6 / \ / \11 9 7 5
解法思路:
1 |
|
代码测试:
1 |
|
题目描述:
输入一个整数数组,判断该数组是不是某二叉搜索树的后序遍历的结果。如果是则输出Yes,否则输出No。假设输入的数组的任意两个数字都互不相同。
解法思路:
1 |
|
代码测试:
1 |
|
题目描述:
给你一根长度为n的绳子,请把绳子剪成整数长的m段(m、n都是整数,n>1并且m>1,m<=n),每段绳子的长度记为 k[1],…,k[m]。请问 k[1]x…xk[m] 可能的最大乘积是多少?例如,当绳子的长度是8时,我们把它剪成长度分别为2、3、3的三段,此时得到的最大乘积是18。
输入:8
输出:18
解法思路:
代码测试:
]]>题目描述:
输入一个整数,输出该数32位二进制表示中1的个数。其中负数用补码表示。
解法思路:
1 |
|
代码测试:
1 |
|
题目描述:
输入一个字符串,按字典序打印出该字符串中字符的所有排列。例如输入字符串abc,则打印出由字符a,b,c所能排列出来的所有字符串abc,acb,bac,bca,cab和cba。
输入一个字符串,长度不超过9(可能有字符重复),字符只包括大小写字母。
解法思路:
1 |
|
代码测试:
1 |
|
题目描述:
求1+2+3+…+n,要求不能使用乘除法、for、while、if、else、switch、case等关键字及条件判断语句(A?B:C)。
解法思路:
1 |
|
代码测试:
1 |
|
题目描述:
给定一个数组A[0,1,…,n-1],请构建一个数组B[0,1,…,n-1],其中B中的元素B[i]=A[0]A[1]…A[i-1]*A[i+1]…*A[n-1]。不能使用除法。(注意:规定B[0] = A[1] * A[2] * … * A[n-1],B[n-1] = A[0] * A[1] * … * A[n-2];)
解法思路:
1 |
|
代码测试:
]]>题目描述:
将一个字符串转换成一个整数,要求不能使用字符串转换整数的库函数。 数值为0或者字符串不是一个合法的数值则返回0
输入描述:
输入一个字符串,包括数字字母符号,可以为空
输出描述:
如果是合法的数值表达则返回该数字,否则返回0
示例:
输入:
+2147483647
1a33
输出:
2147483647
0
解法思路:
使用了一个很巧妙的方法,用一个字典将字符串”0”-“9”与数字0 - 9做一个映射,然后再用数学上计算一个数字的公式得出这个数。比如:123 = (1 * 10 + 2 ) * 10 + 3
。需要注意字符串开头的正负号,从而判断得到的数字是整数还是负数。
1 |
|
代码测试:
1 |
|
题目描述:
大家都知道斐波那契数列,现在要求输入一个整数n,请你输出斐波那契数列的第n项(从0开始,第0项为0,第1项是1)(n<=39)。
解法一思路:
直接根据数学公式f(n) = f(n - 1) + f(n - 2)
,截至条件是当n = 1, f(n) = 1
,n = 0, f(0) = 0
。利用递归法进行求解,这种方法时间复杂度很大,为O(n^2)
,空间复杂度为O(1)
。
1 |
|
解法二思路:
1 |
|
解法三思路:
1 |
|
代码测试:
1 |
|
题目描述:
写一个函数,求两个整数之和,要求在函数体内不得使用+、-、*、/四则运算符号。
解法思路:
1 |
|
代码测试:
1 |
|
题目描述:
输入两个单调递增的链表,输出两个链表合成后的链表,当然我们需要合成后的链表满足单调不减规则。
解法一思路:
使用迭代的方法。先判断临界情况,依次判断输入的两个链表是否为空指针,如果有其中一个为空指针链表,则返回另一个有序的链表。
然后初始化一个新链表,依次比较两个有序链表的值,哪个链表的值较小,则新链表的指针指向该值。继续循环,依次比较,最终返回单调递增的新链表。
1 |
|
解法二思路:
使用递归的方法。大体思路同上,先判断临界情况,依次判断输入的两个链表是否为空指针,如果有其中一个为空指针链表,则返回另一个有序的链表。
然后依次比较两个有序链表的值,哪个链表的值较小,则将该节点赋值给新链表。使用递归,直至其中一个链表为None,最终返回和并得到的单调递增链表。
1 |
|
代码测试:
1 |
|
题目描述:
输入一个链表,输出该链表中倒数第k个结点。
解法一思路:
1 |
|
解法二思路:
1 |
|
代码测试:
1 |
|
题目描述:
输入一个链表,反转链表后,输出新链表的表头。
解法思路:
1 |
|
代码测试:
1 |
|
题目描述:
输入一个链表,按链表从尾到头的顺序返回一个ArrayList。
解法思路:
1 |
|
代码测试:
1 |
|
itertools
, functools
以及operator
。在函数式编程中,我们经常需要把算术运算符当作函数使用,因此可以借助operator模块。operator 模块提供了一套与Python的内置运算符对应的高效率函数。例如,operator.add(x, y) 与表达式 x+y 相同。
operator 模块为多个算术运算符提供了对应的函数,从而避免编写lambda a, b: a * b
这种平凡的匿名函数。这两种做法具体如下:
lambda a, b: a * b
匿名函数来计算阶乘:1 |
|
operator.mul
函数来计算阶乘:1 |
|
operator 模块中还有一类函数,能替代从系列中取出元素或读取对象属性的lambda表达式:
]]>一般编程语言支持通过以下几种方式来解决具体的问题:
一般语言设计者在设计语言时,会选择侧重强调一种特定的编程方式,但这会让以不同方式来编写程序变得困难。因此有些语言就被设计成多范式语言,用以支持以上几种不同的编程方式。其中Lisp,C++ 和 Python 都是多范式语言;使用这些语言,你可以编写主要为过程式,面向对象或者函数式的程序和函数库。在大型程序中,不同的部分可能会采用不同的方式编写;比如 GUI 可能是面向对象的而处理逻辑则是过程式或者函数式。
这篇文章主要是来讲解函数式编程,因此接下来主要围绕函数式编程进行展开。
函数式编程:即为给定输入,输入会流经一系列函数,每个函数接收输入并输出结果。并且这个过程,在每个函数内部并不会修改全局变量或者有其他副作用。函数式编程允许把函数本身作为参数传入另一个函数,还允许返回一个函数。
函数式风格有其理论和实践上的优点:
|
More info: Writing
+
|
More info: Server
+
|
More info: Generating
+
|
More info: Deployment
+]]>今天在使用 golang 重构 python 站点时,遇到了一个有趣的事情。就是在 python 函数中参数是可以设置默认值的,这样在函数调用时,就不需要每个参数都传一个值,其实这也是变相的实现重载功能。但是我发现在 golang 中参数是不能设置默认值的,但是基于程序员的直觉,相信此事没那么简单,于是抱着打破沙锅问到底的态度,就有了这篇文章。
+首先,通过一个例子,说明我在编码过程中遇到的问题。对于平台后端开发工程师来说,会经常遇到以下场景:
通过
基于此,我将这些查询方式抽象成一个方法,之后所有的功能模块,都可以使用该方法进行多条件联合查询数据记录,具体抽象如下:
+
|
kube-apiserver
是 Kubernetes
最重要的核心组件之一,主要能提供的功能如下:
+RESTful API
的形式提供其他组件查询,修改集群状态的 CURD(Create,Read,Update,Detele)
接口,然后将状态储存到 etcd
中;kube-apiserver
提供了 Kubernetes
的 REST API
,实现了认证、授权、准入控制等安全校验功能,同时也负责集群状态的存储操作(通过 etcd
)。
kube-apiserver
提供了为每种语言提供了 SDK
,方便用户访问集群其他组件,以及将数据存储或更新到etcd
中,如下:
Client
.查询 kube-apiserver
支持API
的版本
|
查询 kube-apiserver
支持API
的资源对象
|
查看 kube-apiserver
的 v1/namepsace
信息
|
通过启动 proxy
获取集群配置信息
|
查看集群各组件信息
+
|
在 pod 里面访问
+
|
在 master 节点上访问
+
|
2020,一个不平凡的一年,这整年人人都基本是带着口罩过来的,直到现在还是无法摆脱带口罩,每天出行仍需带着上地铁,进公司。在年初,因为疫情影响,相信很多人都是被困在家远程办公。刚开始在家办公,自己还是不适应的,没有公司的那种开发氛围,很多需求也不能面对面及时的沟通得以解决,这样还是挺不方便的。但是后来,随着在家办公的时间长了,感觉在家办公也不错,至少节省了上下班通勤路上的时间,每天从床上爬起来就可以投入工作,这种感觉还是挺好的。当然这样对于大多数人工作效率肯定是很低的,所以公司还是会尽量要求员工在家隔离完就需要回公司办公了,因此自己大概在今年3月份回到联想大厦办公了。
+其实自己在年初的时候给自己的2020定了一些计划的,但是关于实现与否,还真是偏差甚远。首先是打算这一年换一份工作的,最好是NLP算法工程师相关的工作。在今年的前三个月里,自己还是很认真的在学习NLP相关的知识,但是后面发现自己还是很难去找这相关的工作,加上后面在联想又大部分时间在做开发相关的工作,所以后面也就没再学习了。关于跳槽,从今年8月份开始更新几个网站的简历,然后也是8月份开始陆续接到了很多猎头的电话,也面试了很多了公司,最终拿了几个offer,待遇什么的较联想这边也有一定的涨幅。最后选择了一家互联网+金融的公司,信也科技,但不是算法相关的岗位,不过也挺符合自己的发展方向的,目前主要是机器学习容器云平台开发,主要是
Python / Go 作为技术栈, 基于 Kubernetes / Docker 打造基于云原生上传数据集,标注,特征提取,训练以及模型部署一体化的机器学习平台。
Kubernetes 集群分为两个部分:
+其中控制平面的组件有:
+运行容器任务依赖于每个工作节点上运行的组件,包括:
+
|
代码测试:
+
|
题目描述:
+++请实现一个函数按照之字形打印二叉树,即第一行按照从左到右的顺序打印,第二层按照从右至左的顺序打印,第三行按照从左到右的顺序打印,其他行以此类推。
+
解法思路:
这道题其实是昨天最后一道题JZ60
的升级版,其实也就是层次遍历二叉树(BFS)。层次遍历思想可以参见上一道题,只是此题需要结合二叉树的深度depth
进行解题。在每次需要打印的地方,当深度depth
对2取余,为0则从左到右打印,为1则反转打印。
|
代码测试:
+
|
题目描述:
+++请实现一个函数,用来判断一棵二叉树是不是对称的。注意,如果一个二叉树同此二叉树的镜像是同样的,定义其为对称的。
+
解法思路:
+ +
|
代码测试:
+
|
题目描述:
+++给定一个二叉树和其中的一个结点,请找出中序遍历顺序的下一个结点并且返回。注意,树中的结点不仅包含左右子结点,同时包含指向父结点的指针。
+
解法思路:
+
|
代码测试:
+
|
题目描述:
+++输入一棵二叉树,判断该二叉树是否是平衡二叉树。
+
++在这里,我们只需要考虑其平衡性,不需要考虑其是不是排序二叉树
+
解法思路:
+
|
代码测试:
+
|
题目描述:
+++输入一个矩阵,按照从外向里以顺时针的顺序依次打印出每一个数字,例如,如果输入如下4 X 4矩阵: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 则依次打印出数字1,2,3,4,8,12,16,15,14,13,9,5,6,7,11,10.
+
解法思路:
这道题刚开始自己一看,就是想着设置一些索引位置,按照索引位置打印来打印不就行了。后来再认真读题,发现它输入的二维矩阵大小是变化的,不是固定大小,才发现自己的想法太native
。
看了下讨论区,发现只是需要确定几个固定位置的索引值,便可以不管输入矩阵的大小,自适应的便能够确定顺时针打印每个位置的索引,然后再根据这个索引来打印矩阵就行,还真是巧妙。其实在确定好几个顶点的位置,也就相当于确定了方向,然后不管是顺时针还是逆时针,下次都可以方便的解题了。
+ +
|
代码测试:
+
|
题目描述:
+++输入一棵二叉树,求该树的深度。从根结点到叶结点依次经过的结点(含根、叶结点)形成树的一条路径,最长路径的长度为树的深度。
+
解法思路:
+
|
代码测试:
+
|
题目描述:
+++从上到下按层打印二叉树,同一层结点从左至右输出。每一层输出一行。
+
解法思路:
+
|
代码测试:
+
|
题目描述:
+++把一个数组最开始的若干个元素搬到数组的末尾,我们称之为数组的旋转。
+
输入一个非递减排序的数组的一个旋转,输出旋转数组的最小元素。
例如数组{3,4,5,1,2}为{1,2,3,4,5}的一个旋转,该数组的最小值为1。
NOTE:给出的所有元素都大于0,若数组大小为0,请返回0。
解法思路:
这题主要是考察二分查找。二分查找,又叫折半查找。它的前提是线性表中的数据必须是有序的,线性表必须采用顺序存储。主要思想是:在有序表中,去中间记录作为比较对象,若给定值与中间记录的关键字相等,则查找成功;若给定值小于中间记录的关键字,则在中间记录的左半区继续查找;若给定值大于中间记录的关键字,则在中间记录的右半区继续查找;不断重复上述过程,直至查找成功,或所有查找区域无记录,查找失败为止。
上面介绍了二分查找的主要思路,而本题难点在于找到中间值与谁进行比较? 再认真审下题,给定的是非递减排序的数组,也就是“平序”或升序。例如:[1, 2, 3, 3, 3, 5, 6]
(“平序”),[1, 2, 3, 4, 5, 6]
(升序)。然后再做旋转得到旋转数组[3, 3, 5, 6, 1, 2, 3]
,[4, 5, 6, 1, 2, 3]
,可以确定的是旋转后的数组nums[0] >= nums[-1]
恒成立。
这样也就得到了nums[mid]
与哪个值进行比较了,当然是:
nums[mid] > nums[left]
, 这个时候 left = mid + 1
nums[mid] < nums[right]
, 这个时候 right = mid
nums[mid] = nums[right]
, 这个时候 left += 1
这里可以一定意义上认为nums[left]
与nums[right]
近似相等,这样便于理解。
++ +注: 以上
+nums
代表传入的旋转数组,left
指数组的第一个数,right
指数组末尾的数,mid
指数组中间位置的数。
|
代码测试:
+
|
题目描述:
+++操作给定的二叉树,将其变换为源二叉树的镜像。
+
二叉树的镜像定义如下:
源二叉树
+ 8
+ / \
+ 6 10
+ / \ / \
+5 7 9 11
+
+镜像二叉树
+ 8
+ / \
+ 10 6
+ / \ / \
+11 9 7 5
解法思路:
+
|
代码测试:
+
|
题目描述:
+++输入一个整数数组,判断该数组是不是某二叉搜索树的后序遍历的结果。如果是则输出Yes,否则输出No。假设输入的数组的任意两个数字都互不相同。
+
解法思路:
+
|
代码测试:
+
|
题目描述:
+++给你一根长度为n的绳子,请把绳子剪成整数长的m段(m、n都是整数,n>1并且m>1,m<=n),每段绳子的长度记为 k[1],…,k[m]。请问 k[1]x…xk[m] 可能的最大乘积是多少?例如,当绳子的长度是8时,我们把它剪成长度分别为2、3、3的三段,此时得到的最大乘积是18。
+
++输入:8
+
输出:18
解法思路:
+代码测试:
+]]>题目描述:
+++一只青蛙一次可以跳上1级台阶,也可以跳上2级。求该青蛙跳上一个n级的台阶总共有多少种跳法(先后次序不同算不同的结果)。
+
解法思路:
+ +
|
代码测试:
+
|
题目描述:
+++一只青蛙一次可以跳上1级台阶,也可以跳上2级……它也可以跳上n级。求该青蛙跳上一个n级的台阶总共有多少种跳法。
+
解法思路:
+
|
代码测试:
+
|
题目描述:
+++我们可以用21的小矩形横着或者竖着去覆盖更大的矩形。请问用n个21的小矩形无重叠地覆盖一个2*n的大矩形,总共有多少种方法?
+
解法思路:
+
|
代码测试:
+
|
题目描述:
+++输入两个整数序列,第一个序列表示栈的压入顺序,请判断第二个序列是否可能为该栈的弹出顺序。假设压入栈的所有数字均不相等。
+
例如序列1,2,3,4,5是某栈的压入顺序,序列4,5,3,2,1是该压栈序列对应的一个弹出序列,但4,3,5,1,2就不可能是该压栈序列的弹出序列。
(注意:这两个序列的长度是相等的)
解法思路:
+
|
代码测试:
+]]>题目描述:
+++输入某二叉树的前序遍历和中序遍历的结果,请重建出该二叉树。假设输入的前序遍历和中序遍历的结果中都不含重复的数字。例如输入前序遍历序列 [1,2,4,7,3,5,6,8] 和中序遍历序列 [4,7,2,1,5,3,8,6] ,则重建二叉树并返回。
+
解法思路:
使用递归的方法求解。这道题需要对二叉树的性质比较了解,需要熟悉二叉树的几种遍历方式。
前序遍历是先遍历根节点,然后遍历左节点,最后遍历右节点(根左右)
+中序遍历是先遍历左节点,然后遍历根节点,最后遍历右节点(左根右)
+后序遍历是先遍历左节点,然后遍历右节点,最后遍历根节点(根左右)
+本题给定前序遍历以及中序遍历的序列,可以知道前序遍历第一个值一定是根节点。而根节点在中序遍历中会把左右子树分成两半。因此本题的关键是找到根节点,然后将左右子树依次递归重建得到二叉树。
+使用递归是需要结束条件的,当前序或中序遍历序列为None
时,便可推出递归,得到二叉树。
|
本题只需写好reConstructBinaryTree
这个方法,上面代码其他三个函数是用来前序、中序以及后序遍历重建得到二叉树的,以方便大家调试。
代码测试:
|
题目描述:
+++操作给定的二叉树,将其变换为源二叉树的镜像。
+
二叉树的镜像定义如下:
源二叉树
+ 8
+ / \
+ 6 10
+ / \ / \
+5 7 9 11
+
+镜像二叉树
+ 8
+ / \
+ 10 6
+ / \ / \
+11 9 7 5
解法思路:
+
|
代码测试:
+
|
题目描述:
+++输入一个整数数组,判断该数组是不是某二叉搜索树的后序遍历的结果。如果是则输出Yes,否则输出No。假设输入的数组的任意两个数字都互不相同。
+
解法思路:
+
|
代码测试:
+
|
题目描述:
+++给你一根长度为n的绳子,请把绳子剪成整数长的m段(m、n都是整数,n>1并且m>1,m<=n),每段绳子的长度记为 k[1],…,k[m]。请问 k[1]x…xk[m] 可能的最大乘积是多少?例如,当绳子的长度是8时,我们把它剪成长度分别为2、3、3的三段,此时得到的最大乘积是18。
+
++输入:8
+
输出:18
解法思路:
+代码测试:
+]]>题目描述:
+++输入一个整数,输出该数32位二进制表示中1的个数。其中负数用补码表示。
+
解法思路:
+ +
|
代码测试:
+
|
题目描述:
+++输入一个字符串,按字典序打印出该字符串中字符的所有排列。例如输入字符串abc,则打印出由字符a,b,c所能排列出来的所有字符串abc,acb,bac,bca,cab和cba。
+
++输入一个字符串,长度不超过9(可能有字符重复),字符只包括大小写字母。
+
解法思路:
+
|
代码测试:
+
|
题目描述:
+++求1+2+3+…+n,要求不能使用乘除法、for、while、if、else、switch、case等关键字及条件判断语句(A?B:C)。
+
解法思路:
+
|
代码测试:
+
|
题目描述:
+++给定一个数组A[0,1,…,n-1],请构建一个数组B[0,1,…,n-1],其中B中的元素B[i]=A[0]A[1]…A[i-1]*A[i+1]…*A[n-1]。不能使用除法。(注意:规定B[0] = A[1] * A[2] * … * A[n-1],B[n-1] = A[0] * A[1] * … * A[n-2];)
+
解法思路:
+
|
代码测试:
+]]>题目描述:
+++将一个字符串转换成一个整数,要求不能使用字符串转换整数的库函数。 数值为0或者字符串不是一个合法的数值则返回0
+
输入描述:
输入一个字符串,包括数字字母符号,可以为空
输出描述:
如果是合法的数值表达则返回该数字,否则返回0
++示例:
+
输入:
+2147483647
1a33
输出:
2147483647
0
解法思路:
使用了一个很巧妙的方法,用一个字典将字符串”0”-“9”与数字0 - 9做一个映射,然后再用数学上计算一个数字的公式得出这个数。比如:123 = (1 * 10 + 2 ) * 10 + 3
。需要注意字符串开头的正负号,从而判断得到的数字是整数还是负数。
|
代码测试:
+
|
题目描述:
+++大家都知道斐波那契数列,现在要求输入一个整数n,请你输出斐波那契数列的第n项(从0开始,第0项为0,第1项是1)(n<=39)。
+
解法一思路:
直接根据数学公式f(n) = f(n - 1) + f(n - 2)
,截至条件是当n = 1, f(n) = 1
,n = 0, f(0) = 0
。利用递归法进行求解,这种方法时间复杂度很大,为O(n^2)
,空间复杂度为O(1)
。
|
解法二思路:
+
|
解法三思路:
+
|
代码测试:
+
|
题目描述:
+++写一个函数,求两个整数之和,要求在函数体内不得使用+、-、*、/四则运算符号。
+
解法思路:
+
|
代码测试:
+
|
题目描述:
+++输入两个单调递增的链表,输出两个链表合成后的链表,当然我们需要合成后的链表满足单调不减规则。
+
解法一思路:
使用迭代的方法。先判断临界情况,依次判断输入的两个链表是否为空指针,如果有其中一个为空指针链表,则返回另一个有序的链表。
然后初始化一个新链表,依次比较两个有序链表的值,哪个链表的值较小,则新链表的指针指向该值。继续循环,依次比较,最终返回单调递增的新链表。
+
|
解法二思路:
使用递归的方法。大体思路同上,先判断临界情况,依次判断输入的两个链表是否为空指针,如果有其中一个为空指针链表,则返回另一个有序的链表。
然后依次比较两个有序链表的值,哪个链表的值较小,则将该节点赋值给新链表。使用递归,直至其中一个链表为None,最终返回和并得到的单调递增链表。
+ +
|
代码测试:
+
|
题目描述:
+++输入一个链表,输出该链表中倒数第k个结点。
+
解法一思路:
+
|
解法二思路:
+
|
代码测试:
+
|
题目描述:
+++输入一个链表,反转链表后,输出新链表的表头。
+
解法思路:
+
|
代码测试:
+
|
题目描述:
+++输入一个链表,按链表从尾到头的顺序返回一个ArrayList。
+
解法思路:
+
|
代码测试:
+
|
itertools
, functools
以及operator
。
+在函数式编程中,我们经常需要把算术运算符当作函数使用,因此可以借助operator模块。operator 模块提供了一套与Python的内置运算符对应的高效率函数。例如,operator.add(x, y) 与表达式 x+y 相同。
+operator 模块为多个算术运算符提供了对应的函数,从而避免编写lambda a, b: a * b
这种平凡的匿名函数。这两种做法具体如下:
lambda a, b: a * b
匿名函数来计算阶乘:
|
operator.mul
函数来计算阶乘:
|
operator 模块中还有一类函数,能替代从系列中取出元素或读取对象属性的lambda表达式:
+]]>一般编程语言支持通过以下几种方式来解决具体的问题:
+一般语言设计者在设计语言时,会选择侧重强调一种特定的编程方式,但这会让以不同方式来编写程序变得困难。因此有些语言就被设计成多范式语言,用以支持以上几种不同的编程方式。其中Lisp,C++ 和 Python 都是多范式语言;使用这些语言,你可以编写主要为过程式,面向对象或者函数式的程序和函数库。在大型程序中,不同的部分可能会采用不同的方式编写;比如 GUI 可能是面向对象的而处理逻辑则是过程式或者函数式。
+这篇文章主要是来讲解函数式编程,因此接下来主要围绕函数式编程进行展开。
+函数式编程:即为给定输入,输入会流经一系列函数,每个函数接收输入并输出结果。并且这个过程,在每个函数内部并不会修改全局变量或者有其他副作用。函数式编程允许把函数本身作为参数传入另一个函数,还允许返回一个函数。
+函数式风格有其理论和实践上的优点:
+共计 4 篇文章
+2021
+ + + +2020
+ + + +共计 11 篇文章
+2020
+ + + +