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 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + My first post - LuckyCrise + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ + + + + + +
+ +
+ +
+ + + +
+
+
+ + +
+ +
+
+
+
+ +

My first post

+ + +
+ + + +
+ +
+
+ + + + + + +
+
+
My first post
+
https://crisescode.github.io/blog/2020/06/18/My-first-post/
+
+
+ +
+
作者
+
Crise
+
+ + +
+
发布于
+
2020年6月18日
+
+ + + +
+
许可协议
+
+ + + + + + + + + + +
+
+ +
+
+
+ + + + +
+ +
+ + +
+
+ +
+ + +
+ +
+
+ + + + +
+ + +
+ + +
+
+
+
+ +
+ + + + +
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git "a/2020/06/19/Python\344\271\213\345\207\275\346\225\260\345\274\217\347\274\226\347\250\213\346\250\241\345\235\227/index.html" "b/2020/06/19/Python\344\271\213\345\207\275\346\225\260\345\274\217\347\274\226\347\250\213\346\250\241\345\235\227/index.html" new file mode 100644 index 0000000..69f9dd2 --- /dev/null +++ "b/2020/06/19/Python\344\271\213\345\207\275\346\225\260\345\274\217\347\274\226\347\250\213\346\250\241\345\235\227/index.html" @@ -0,0 +1,786 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Python之函数式编程模块(1) - LuckyCrise + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ + + + + + +
+ +
+ +
+ + + +
+
+
+ + +
+ +
+
+
+
+ +

Python之函数式编程模块(1)

+ + +
+ +

一、编程方式介绍

一般编程语言支持通过以下几种方式来解决具体的问题:

+
    +
  • 大多数的编程语言都是过程式的,也就是我们常说的面向过程的编程方式。而所谓程序是指令的列表,告诉计算机如何处理程序的输入。C、Pascal甚至Unix shell都是过程式语言。
  • +
  • 然后有一些编程语言是声明式的,主要是你需要编写一个用来描述待解决问题的说明,然后这个语言的具体实现会指明怎样高效的进行计算并解决问题。SQL 可能是你最熟悉的声明式语言了。 一个 SQL 查询语句描述了你想要检索的数据集,并且 SQL 引擎会决定是扫描整张表还是使用索引,应该先执行哪些子句等等。
  • +
  • 面向对象编程语言会操作一组对象。其中对象拥有内部状态,并能够以某种方式支持请求和修改这个内部状态的方法。Smalltalk 和 Java 都是面向对象的语言。C++ 和 Python 支持面向对象编程,但并不强制使用面向对象特性。
  • +
  • 函数式编程则是将一个问题分解成一系列函数。理想情况下,函数只接受输入并产生输出,没有任何内部状态会影响为给定输入产生的输出。众所周知的函数式语言包括ML家族(标准ML、OCaml和其他变体)和Haskell。
  • +
+ + +

一般语言设计者在设计语言时,会选择侧重强调一种特定的编程方式,但这会让以不同方式来编写程序变得困难。因此有些语言就被设计成多范式语言,用以支持以上几种不同的编程方式。其中Lisp,C++ 和 Python 都是多范式语言;使用这些语言,你可以编写主要为过程式,面向对象或者函数式的程序和函数库。在大型程序中,不同的部分可能会采用不同的方式编写;比如 GUI 可能是面向对象的而处理逻辑则是过程式或者函数式。

+

这篇文章主要是来讲解函数式编程,因此接下来主要围绕函数式编程进行展开。

+

二、函数式编程

2.1 定义

函数式编程:即为给定输入,输入会流经一系列函数,每个函数接收输入并输出结果。并且这个过程,在每个函数内部并不会修改全局变量或者有其他副作用。函数式编程允许把函数本身作为参数传入另一个函数,还允许返回一个函数。

+

2.2 特点

函数式风格有其理论和实践上的优点:

+
    +
  • 形式证明
  • +
  • 模块化
  • +
  • 组合性
  • +
  • 易于调试和测试
  • +
+

三、函数式编程实践

3.1

+ +
+ +
+
+ + + + + + +
+
+
Python之函数式编程模块(1)
+
https://crisescode.github.io/blog/2020/06/19/Python之函数式编程模块/
+
+
+ +
+
作者
+
Crise
+
+ + +
+
发布于
+
2020年6月19日
+
+ + + +
+
许可协议
+
+ + + + + + + + + + +
+
+ +
+
+
+ + + + +
+ + +
+ +
+ + +
+ +
+
+ + + + +
+ + +
+ + +
+
+
+
+ +
+ + + + +
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git "a/2020/06/19/Python\344\271\213\345\207\275\346\225\260\345\274\217\347\274\226\347\250\213\346\250\241\345\235\227\357\274\2102\357\274\211/index.html" "b/2020/06/19/Python\344\271\213\345\207\275\346\225\260\345\274\217\347\274\226\347\250\213\346\250\241\345\235\227\357\274\2102\357\274\211/index.html" new file mode 100644 index 0000000..6692f38 --- /dev/null +++ "b/2020/06/19/Python\344\271\213\345\207\275\346\225\260\345\274\217\347\274\226\347\250\213\346\250\241\345\235\227\357\274\2102\357\274\211/index.html" @@ -0,0 +1,782 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Python之函数式编程模块(2) - LuckyCrise + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ + + + + + +
+ +
+ +
+ + + +
+
+
+ + +
+ +
+
+
+
+ +

Python之函数式编程模块(2)

+ + +
+ +

这篇文章主要是讲解一些函数式编程常用的模块,比如:itertools, functools以及operator

+

一、itertools –用以创建迭代器的模块

+ +

二、functools – 高阶函数可调用对象上的操作

三、operator – 标准运算符替代函数

在函数式编程中,我们经常需要把算术运算符当作函数使用,因此可以借助operator模块。operator 模块提供了一套与Python的内置运算符对应的高效率函数。例如,operator.add(x, y) 与表达式 x+y 相同。

+

operator 模块为多个算术运算符提供了对应的函数,从而避免编写
lambda a, b: a * b 这种平凡的匿名函数。这两种做法具体如下:

+
    +
  • 使用lambda a, b: a * b匿名函数来计算阶乘:
  • +
+
1
2
3
4
5
6
7
8
>>> from functools import reduce
>>> from operator import mul
>>> def fact(n):
... return reduce(mul, range(1, n+1))
...
>>> fact(5)
120

+
    +
  • 使用operator.mul函数来计算阶乘:
  • +
+
1
2
3
4
5
6
7
8
>>> from functools import reduce
>>> from operator import mul
>>> def fact(n):
... return reduce(mul, range(1, n+1))
...
>>> fact(5)
120

+ +

operator 模块中还有一类函数,能替代从系列中取出元素或读取对象属性的lambda表达式:

+ + +
+ +
+
+ + + + + + +
+
+
Python之函数式编程模块(2)
+
https://crisescode.github.io/blog/2020/06/19/Python之函数式编程模块(2)/
+
+
+ +
+
作者
+
Crise
+
+ + +
+
发布于
+
2020年6月19日
+
+ + + +
+
许可协议
+
+ + + + + + + + + + +
+
+ +
+
+
+ + + + +
+ + +
+ +
+ + +
+ +
+
+ + + + +
+ + +
+ + +
+
+
+
+ +
+ + + + +
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git "a/2020/06/27/NLP\357\274\2101\357\274\211\346\226\207\346\234\254\345\210\206\347\261\273\347\237\245\350\257\206\346\242\263\347\220\206/index.html" "b/2020/06/27/NLP\357\274\2101\357\274\211\346\226\207\346\234\254\345\210\206\347\261\273\347\237\245\350\257\206\346\242\263\347\220\206/index.html" new file mode 100644 index 0000000..25e7792 --- /dev/null +++ "b/2020/06/27/NLP\357\274\2101\357\274\211\346\226\207\346\234\254\345\210\206\347\261\273\347\237\245\350\257\206\346\242\263\347\220\206/index.html" @@ -0,0 +1,771 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + NLP(1)文本分类知识梳理 - LuckyCrise + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ + + + + + +
+ +
+ +
+ + + +
+
+
+ + +
+ +
+
+
+
+ +

NLP(1)文本分类知识梳理

+ + +
+ + + +
+ +
+
+ + + + + + +
+
+
NLP(1)文本分类知识梳理
+
https://crisescode.github.io/blog/2020/06/27/NLP(1)文本分类知识梳理/
+
+
+ +
+
作者
+
Crise
+
+ + +
+
发布于
+
2020年6月27日
+
+ + + +
+
许可协议
+
+ + + + + + + + + + +
+
+ +
+
+
+ + + + +
+ + +
+ +
+ + +
+ +
+
+ + + + +
+ + +
+ + +
+
+
+
+ +
+ + + + +
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git "a/2020/07/06/\345\211\221\346\214\207offer-\347\254\254\344\270\200\345\244\251/index.html" "b/2020/07/06/\345\211\221\346\214\207offer-\347\254\254\344\270\200\345\244\251/index.html" new file mode 100644 index 0000000..f5cc5e7 --- /dev/null +++ "b/2020/07/06/\345\211\221\346\214\207offer-\347\254\254\344\270\200\345\244\251/index.html" @@ -0,0 +1,805 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 剑指offer 第一天 - LuckyCrise + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ + + + + + +
+ +
+ +
+ + + +
+
+
+ + +
+ +
+
+
+
+ +

剑指offer 第一天

+ + +
+ +

JZ16 合并两个排序的链表

题目描述:

+
+

输入两个单调递增的链表,输出两个链表合成后的链表,当然我们需要合成后的链表满足单调不减规则。

+
+

解法一思路:
使用迭代的方法。先判断临界情况,依次判断输入的两个链表是否为空指针,如果有其中一个为空指针链表,则返回另一个有序的链表。

+

然后初始化一个新链表,依次比较两个有序链表的值,哪个链表的值较小,则新链表的指针指向该值。继续循环,依次比较,最终返回单调递增的新链表。

+
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
class ListNode:
def __init__(self, x):
self.val = x
self.next = None


class Solution2:
# 返回合并后列表
def Merge(self, pHead1, pHead2):
# write code here
if pHead1 is None:
return pHead2
if pHead2 is None:
return pHead1

node = sorted_node = ListNode(0)

while pHead1 and pHead2:
if pHead1.val < pHead2.val:
node.next = pHead1
pHead1 = pHead1.next
else:
node.next = pHead2
pHead2 = pHead2.next
node = node.next

if pHead1 or pHead2:
node.next = pHead1 or pHead2

return sorted_node.next

def travel_list(self, node):
while node is not None:
print(node.val, end=" ")
node = node.next
+

解法二思路:
使用递归的方法。大体思路同上,先判断临界情况,依次判断输入的两个链表是否为空指针,如果有其中一个为空指针链表,则返回另一个有序的链表。

+

然后依次比较两个有序链表的值,哪个链表的值较小,则将该节点赋值给新链表。使用递归,直至其中一个链表为None,最终返回和并得到的单调递增链表。

+ +
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
class ListNode:
def __init__(self, x):
self.val = x
self.next = None

class Solution:
# 返回合并后列表
def Merge(self, pHead1, pHead2):
# write code here
if pHead1 is None:
return pHead2
if pHead2 is None:
return pHead1

if pHead1.val < pHead2.val:
sorted_list = pHead1
sorted_list.next = self.Merge(pHead1.next, pHead2)
else:
sorted_list = pHead2
sorted_list.next = self.Merge(pHead1, pHead2.next)

return sorted_list

def travel_list(self, node):
while node is not None:
print(node.val, end=" ")
node = node.next
+

代码测试:

+
1
2
3
4
5
6
7
8
9
10
11
12
13
if __name__ == "__main__":
node_1 = ListNode(0)
node_1.next = ListNode(4)
node_1.next.next = ListNode(10)
node_2 = ListNode(2)
node_2.next = ListNode(3)
node_2.next.next = ListNode(12)
solu_1 = Solution()
# print(solu_1.travel_list(solu_1.Merge(node_1, node_2)))
solu_2 = Solution2()
print(solu_2.travel_list(solu_2.Merge(node_1, node_2)))

>>> 0 2 3 4 10 12 None
+ +

JZ14 链表中倒数第k个结点

题目描述:

+
+

输入一个链表,输出该链表中倒数第k个结点。

+
+

解法一思路:

+
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
lass ListNode:
def __init__(self, x):
self.val = x
self.next = None


class Solution:
# 时间复杂度: O(n)
# 空间复杂度: O(n)
def FindKthToTail(self, head, k):
# write code here
res = []

while head is not None:
res.insert(0, head.val)
head = head.next

if len(res) < k or k < 1:
return

return res[k-1]

def travel_listNode(self, listNode):
while listNode:
print(listNode.val, end=" ")
listNode = listNode.next
+ +

解法二思路:

+
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
class Solution2:
# 时间复杂度: O(n)
# 空间复杂度: O(1)
def FindKthToTail(self, head, k):
# write code here
if k < 0 or head is None:
return

slow, fast = head, head
count = 0
while fast.next is not None:
fast = fast.next
if count >= k - 1:
slow = slow.next
count += 1

if count >= k - 1:
return slow.val

return None
+

代码测试:

+
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
if __name__ == "__main__":
curr = head = ListNode(0)
head.next = ListNode(1)
head = head.next
head.next = ListNode(2)
head = head.next
head.next = ListNode(3)
head = head.next
head.next = ListNode(4)

print(Solution().travel_listNode(curr))
print(Solution().FindKthToTail(curr, 5))
print(Solution2().FindKthToTail(curr, 5))

>>> 0 1 2 3 4 None
>>> 0
>>> 0
+

JZ15 反转链表

题目描述:

+
+

输入一个链表,反转链表后,输出新链表的表头。

+
+

解法思路:

+
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
class ListNode:
def __init__(self, x):
self.val = x
self.next = None


class Solution:
# 返回ListNode
def ReverseList(self, pHead):
# write code here
if not pHead or pHead.next is None:
return pHead

curr, prev = pHead, None
while curr:
tmp = curr.next
curr.next = prev
prev = curr
curr = tmp

return prev
+

代码测试:

+
1
2
3
4
5
6
7
8
9
10
11
12
13
if __name__ == "__main__":
curr = head = ListNode(0)
head.next = ListNode(1)
head = head.next
head.next = ListNode(2)
head = head.next
head.next = ListNode(3)
head = head.next
# print(head)
print(curr)

res = Solution().ReverseList(curr)
print(res)
+ +

JZ13 从尾到头打印链表

题目描述:

+
+

输入一个链表,按链表从尾到头的顺序返回一个ArrayList。

+
+

解法思路:

+
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
class ListNode:
def __init__(self, x):
self.val = x
self.next = None


class Solution:
# 返回从尾部到头部的列表值序列,例如[1,2,3]
def printListFromTailToHead(self, listNode):
# write code here
res = []
while listNode:
res.insert(0, listNode.val)
listNode = listNode.next

return res

def travel_listNode(self, listNode):
while listNode:
print(listNode.val, end=" ")
listNode = listNode.next
+

代码测试:

+
1
2
3
4
5
6
7
8
9
10
11
12
if __name__ == "__main__":
curr = head = ListNode(0)
head.next = ListNode(1)
head = head.next
head.next = ListNode(2)
head = head.next
head.next = ListNode(3)
head = head.next
head.next = ListNode(4)

print(Solution().travel_listNode(curr))
print(Solution().printListFromTailToHead(curr))
+ +
+ +
+
+ + + + + + +
+
+
剑指offer 第一天
+
https://crisescode.github.io/blog/2020/07/06/剑指offer-第一天/
+
+
+ +
+
作者
+
Crise
+
+ + +
+
发布于
+
2020年7月6日
+
+ + + +
+
许可协议
+
+ + + + + + + + + + +
+
+ +
+
+
+ + + + +
+ + +
+ +
+ + +
+ +
+
+ + + + +
+ + +
+ + +
+
+
+
+ +
+ + + + +
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git "a/2020/07/07/\345\211\221\346\214\207offer\347\254\254\344\272\214\345\244\251/index.html" "b/2020/07/07/\345\211\221\346\214\207offer\347\254\254\344\272\214\345\244\251/index.html" new file mode 100644 index 0000000..c8384c8 --- /dev/null +++ "b/2020/07/07/\345\211\221\346\214\207offer\347\254\254\344\272\214\345\244\251/index.html" @@ -0,0 +1,798 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 剑指offer 第二天 - LuckyCrise + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ + + + + + +
+ +
+ +
+ + + +
+
+
+ + +
+ +
+
+
+
+ +

剑指offer 第二天

+ + +
+ +

JZ49 把字符串转化成整数

题目描述:

+
+

将一个字符串转换成一个整数,要求不能使用字符串转换整数的库函数。 数值为0或者字符串不是一个合法的数值则返回0
输入描述:
输入一个字符串,包括数字字母符号,可以为空
输出描述:
如果是合法的数值表达则返回该数字,否则返回0

+
+
+

示例:
输入:
+2147483647
1a33
输出:
2147483647
0

+
+

解法思路:
使用了一个很巧妙的方法,用一个字典将字符串”0”-“9”与数字0 - 9做一个映射,然后再用数学上计算一个数字的公式得出这个数。比如:123 = (1 * 10 + 2 ) * 10 + 3。需要注意字符串开头的正负号,从而判断得到的数字是整数还是负数。

+ +
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
class Solution:
def StrToInt(self, s):
# write code here
if len(s) == 0:
return 0

str2num = {
"0": 0, "1": 1, "2": 2, "3": 3, "4": 4,
"5": 5, "6": 6, "7": 7, "8": 8, "9": 9,
"+": 1, "-": -1
}

sum = 0
sign = 1
for c in s:
if c in str2num:
if c == "+":
sign = str2num["+"]
continue
if c == "-":
sign = str2num["-"]
continue
sum = sum * 10 + str2num[c]
else:
sum = 0
break

return sum * sign
+

代码测试:

+
1
2
3
4
5
if __name__ == "__main__":
s = "-98210"
print(Solution().StrToInt(s))

>>> 98210
+ +

JZ7 斐波那契数列

题目描述:

+
+

大家都知道斐波那契数列,现在要求输入一个整数n,请你输出斐波那契数列的第n项(从0开始,第0项为0,第1项是1)(n<=39)。

+
+

解法一思路:
直接根据数学公式f(n) = f(n - 1) + f(n - 2),截至条件是当n = 1, f(n) = 1n = 0, f(0) = 0。利用递归法进行求解,这种方法时间复杂度很大,为O(n^2),空间复杂度为O(1)

+
1
2
3
4
5
6
7
class Solution:
def Fibonacci(self, n):
# write code here
if n <= 1:
return n
else:
return self.Fibonacci(n-1) + self.Fibonacci(n-2)
+ +

解法二思路:

+
1
2
3
4
5
6
7
8
9
10
11
12
13
class Solution2:
def Fibonacci(self, n):
# write code here
if n <= 1:
return n

n1, n2, n3 = 0, 1, 0
for i in range(1, n):
n3 = n1 + n2
n1 = n2
n2 = n3

return n3
+

解法三思路:

+
1
2
3
4
5
6
7
8
9
10
11
12
class Solution3:
def Fibonacci(self, n):
# write code here
if n <= 1:
return n

sum, one = 1, 0
for i in range(1, n):
sum = sum + one
one = sum - one

return sum
+ +

代码测试:

+
1
2
3
4
5
6
7
8
if __name__ == "__main__":
print(Solution().Fibonacci(8))
print(Solution2().Fibonacci(8))
print(Solution3().Fibonacci(8))

>>> 21
>>> 21
>>> 21
+

JZ48 不用加减乘除做加法

题目描述:

+
+

写一个函数,求两个整数之和,要求在函数体内不得使用+、-、*、/四则运算符号。

+
+

解法思路:

+
1
2
3
4
class Solution:
def Add(self, num1, num2):
# write code here
pass
+

代码测试:

+
1

+ +
+ +
+
+ + + + + + +
+
+
剑指offer 第二天
+
https://crisescode.github.io/blog/2020/07/07/剑指offer第二天/
+
+
+ +
+
作者
+
Crise
+
+ + +
+
发布于
+
2020年7月7日
+
+ + + +
+
许可协议
+
+ + + + + + + + + + +
+
+ +
+
+
+ + + + +
+ + +
+ +
+ + +
+ +
+
+ + + + +
+ + +
+ + +
+
+
+
+ +
+ + + + +
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git "a/2020/07/08/\345\211\221\346\214\207offer-\347\254\254\344\270\211\345\244\251/index.html" "b/2020/07/08/\345\211\221\346\214\207offer-\347\254\254\344\270\211\345\244\251/index.html" new file mode 100644 index 0000000..3aa0771 --- /dev/null +++ "b/2020/07/08/\345\211\221\346\214\207offer-\347\254\254\344\270\211\345\244\251/index.html" @@ -0,0 +1,803 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 剑指offer 第三天 - LuckyCrise + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ + + + + + +
+ +
+ +
+ + + +
+
+
+ + +
+ +
+
+
+
+ +

剑指offer 第三天

+ + +
+ +

JZ11 二进制中1的个数

题目描述:

+
+

输入一个整数,输出该数32位二进制表示中1的个数。其中负数用补码表示。

+
+

解法思路:

+ +
1
2
3
4
5
6
7
8
9
10
11
12
def NumberOf1(self, n):
# write code here
count = 0

if n < 0:
n = n & 0b11111111111111111111111111111111

while n != 0:
count += 1
n = n & (n - 1)

return count
+

代码测试:

+
1
2
3
4
if __name__ == "__main__":
print(Solution().NumberOf1(-11))

>>> 30
+ +

JZ27 字符串的排列

题目描述:

+
+

输入一个字符串,按字典序打印出该字符串中字符的所有排列。例如输入字符串abc,则打印出由字符a,b,c所能排列出来的所有字符串abc,acb,bac,bca,cab和cba。

+
+
+

输入一个字符串,长度不超过9(可能有字符重复),字符只包括大小写字母。

+
+

解法思路:

+
1
2
3
4
class Solution:
def Permutation(self, ss):
# write code here
pass
+ +

代码测试:

+
1

+

JZ47 求1 + 2 + 3 + … + n

题目描述:

+
+

求1+2+3+…+n,要求不能使用乘除法、for、while、if、else、switch、case等关键字及条件判断语句(A?B:C)。

+
+

解法思路:

+
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
class Solution:
def Sum_Solution(self, n):
# write code here
res = n
try:
res % n
res += self.Sum_Solution(n - 1)
except ZeroDivisionError:
return 0

return res


class Solution2:
def Sum_Solution(self, n):
# write code here
res = n
tmp = (res and self.Sum_Solution(n - 1))
res += tmp

return res
+

代码测试:

+
1
2
3
4
5
6
if __name__ == "__main__":
print(Solution().Sum_Solution(5))
print(Solution2().Sum_Solution(6))

>>> 15
21
+ +

JZ51 构建乘积数组

题目描述:

+
+

给定一个数组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
2
3
4
class Solution:
def multiply(self, A):
# write code here
pass
+ +

代码测试:

+ + +
+ +
+
+ + + + + + +
+
+
剑指offer 第三天
+
https://crisescode.github.io/blog/2020/07/08/剑指offer-第三天/
+
+
+ +
+
作者
+
Crise
+
+ + +
+
发布于
+
2020年7月8日
+
+ + + +
+
许可协议
+
+ + + + + + + + + + +
+
+ +
+
+
+ + + + +
+ + +
+ +
+ + +
+ +
+
+ + + + +
+ + +
+ + +
+
+
+
+ +
+ + + + +
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git "a/2020/07/11/\345\211\221\346\214\207offer-\347\254\254\345\233\233\345\244\251/index.html" "b/2020/07/11/\345\211\221\346\214\207offer-\347\254\254\345\233\233\345\244\251/index.html" new file mode 100644 index 0000000..5b6bfe8 --- /dev/null +++ "b/2020/07/11/\345\211\221\346\214\207offer-\347\254\254\345\233\233\345\244\251/index.html" @@ -0,0 +1,817 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 剑指offer 第四天 - LuckyCrise + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ + + + + + +
+ +
+ +
+ + + +
+
+
+ + +
+ +
+
+
+
+ +

剑指offer 第四天

+ + +
+ +

JZ4 重建二叉树

题目描述:

+
+

输入某二叉树的前序遍历和中序遍历的结果,请重建出该二叉树。假设输入的前序遍历和中序遍历的结果中都不含重复的数字。例如输入前序遍历序列 [1,2,4,7,3,5,6,8] 和中序遍历序列 [4,7,2,1,5,3,8,6] ,则重建二叉树并返回。

+
+

解法思路:
使用递归的方法求解。这道题需要对二叉树的性质比较了解,需要熟悉二叉树的几种遍历方式。

+

前序遍历是先遍历根节点,然后遍历左节点,最后遍历右节点(根左右)

+

中序遍历是先遍历左节点,然后遍历根节点,最后遍历右节点(左根右)

+

后序遍历是先遍历左节点,然后遍历右节点,最后遍历根节点(根左右)

+

本题给定前序遍历以及中序遍历的序列,可以知道前序遍历第一个值一定是根节点。而根节点在中序遍历中会把左右子树分成两半。因此本题的关键是找到根节点,然后将左右子树依次递归重建得到二叉树。

+

使用递归是需要结束条件的,当前序或中序遍历序列为None时,便可推出递归,得到二叉树。

+ +
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
class TreeNode:
def __init__(self, x):
self.val = x
self.left = None
self.right = None


class Solution:
# 返回构造的TreeNode根节点
def reConstructBinaryTree(self, pre, tin):
if not pre or not tin:
return None

root = TreeNode(pre.pop(0))
index = tin.index(root.val)

root.left = self.reConstructBinaryTree(pre, tin[:index])
root.right = self.reConstructBinaryTree(pre, tin[index + 1:])

return root

def preOrder(self, root):
if root is None:
return

print(root.val, end=' ')
self.preOrder(root.left)
self.preOrder(root.right)

def InOrder(self, root):
if root is None:
return
self.InOrder(root.left)
print(root.val, end=' ')
self.InOrder(root.right)

def BackOrder(self, root):
if root is None:
return
self.BackOrder(root.left)
self.BackOrder(root.right)
print(root.val, end=' ')
+

本题只需写好reConstructBinaryTree这个方法,上面代码其他三个函数是用来前序、中序以及后序遍历重建得到二叉树的,以方便大家调试。
代码测试:

+
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
if __name__ == "__main__":
pre = [1, 2, 4, 7, 3, 5, 6, 8]
tin = [4, 7, 2, 1, 5, 3, 8, 6]

reTree = Solution().reConstructBinaryTree(pre, tin)
print("前序遍历:")
Solution().preOrder(reTree)
print("\n")
print("中序遍历:")
Solution().InOrder(reTree)
print("\n")
print("后序遍历:")
Solution().BackOrder(reTree)

>>> 前序遍历:
1 2 4 7 3 5 6 8

中序遍历:
4 7 2 1 5 3 8 6

后序遍历:
7 4 2 5 8 6 3 1

+ +

JZ18 二叉树的镜像

题目描述:

+
+

操作给定的二叉树,将其变换为源二叉树的镜像。
二叉树的镜像定义如下:

+
+
 源二叉树
+    8
+   /  \
+  6   10
+ / \  / \
+5  7 9 11
+
+镜像二叉树
+     8
+   /  \
+  10   6
+ / \  / \
+11 9 7  5

解法思路:

+
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
class TreeNode:
def __init__(self, x):
self.val = x
self.left = None
self.right = None


class Solution:
# 返回镜像树的根节点
def Mirror(self, root):
# write code here
if root is None:
return

root.left, root.right = \
self.Mirror(root.right), self.Mirror(root.left)

return root

def preOrder(self, root):
if root is None:
return

print(root.val, end=' ')
self.preOrder(root.left)
self.preOrder(root.right)
+

代码测试:

+
1
2
3
4
5
6
7
8
9
10
11
12
13
if __name__ == "__main__":
tree1 = TreeNode(8)
tree1.left = TreeNode(6)
tree1.right = TreeNode(10)
tree1.left.left = TreeNode(5)
tree1.left.right = TreeNode(7)
tree1.right.left = TreeNode(9)
tree1.right.right = TreeNode(11)

invert_tree = Solution().Mirror(tree1)
print(Solution().preOrder(invert_tree))

>>> 8 10 11 9 6 7 5 None
+

JZ23 二叉搜索树的后序遍历

题目描述:

+
+

输入一个整数数组,判断该数组是不是某二叉搜索树的后序遍历的结果。如果是则输出Yes,否则输出No。假设输入的数组的任意两个数字都互不相同。

+
+

解法思路:

+
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
class Solution:
def VerifySquenceOfBST(self, sequence):
# write code here
if len(sequence) == 0:
return False

root = sequence[-1]
for index, value in enumerate(sequence):
if value > root:
break

for value in sequence[index: -1]:
if value < root:
return False

left = True
if index > 0:
left = self.VerifySquenceOfBST(sequence[:index])

right = True
if index < len(sequence) - 1:
right = self.VerifySquenceOfBST(sequence[index: -1])

return left and right
+

代码测试:

+
1
2
3
4
5
if __name__ == "__main__":
is_binary_tree = [1, 3, 5, 9, 12, 10, 7]
print(Solution().VerifySquenceOfBST(is_binary_tree))

>>> True
+ +

JZ67 剪绳子

题目描述:

+
+

给你一根长度为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

+
+

解法思路:

+

代码测试:

+ + +
+ +
+
+ + + + + + +
+
+
剑指offer 第四天
+
https://crisescode.github.io/blog/2020/07/11/剑指offer-第四天/
+
+
+ +
+
作者
+
Crise
+
+ + +
+
发布于
+
2020年7月11日
+
+ + + +
+
许可协议
+
+ + + + + + + + + + +
+
+ +
+
+
+ + + + +
+ + +
+ +
+ + +
+ +
+
+ + + + +
+ + +
+ + +
+
+
+
+ +
+ + + + +
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git "a/2020/07/13/\345\211\221\346\214\207offer-\347\254\254\344\272\224\345\244\251/index.html" "b/2020/07/13/\345\211\221\346\214\207offer-\347\254\254\344\272\224\345\244\251/index.html" new file mode 100644 index 0000000..de944b5 --- /dev/null +++ "b/2020/07/13/\345\211\221\346\214\207offer-\347\254\254\344\272\224\345\244\251/index.html" @@ -0,0 +1,799 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 剑指offer 第五天 - LuckyCrise + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ + + + + + +
+ +
+ +
+ + + +
+
+
+ + +
+ +
+
+
+
+ +

剑指offer 第五天

+ + +
+ +

JZ8 跳台阶

题目描述:

+
+

一只青蛙一次可以跳上1级台阶,也可以跳上2级。求该青蛙跳上一个n级的台阶总共有多少种跳法(先后次序不同算不同的结果)。

+
+

解法思路:

+ +
1
2
3
4
5
6
7
8
9
10
11
12
class Solution:
def jumpFloor(self, number):
# write code here
if number <= 2:
return number

res, counter = 1, 0
for i in range(1, number + 1):
res = res + counter
counter = res - counter

return res
+

代码测试:

+
1
2
3
4
5
if __name__ == "__main__":
print(Solution().jumpFloor(3))

>>> 3

+ +

JZ9 变态跳台阶

题目描述:

+
+

一只青蛙一次可以跳上1级台阶,也可以跳上2级……它也可以跳上n级。求该青蛙跳上一个n级的台阶总共有多少种跳法。

+
+

解法思路:

+
1
2
3
4
5
6
7
8
9
10
11
12
class Solution:
def jumpFloor(self, number):
# write code here
if number <= 2:
return number

curr, prev = 1, 1
for i in range(1, number):
curr = 2 * prev
prev = curr

return curr
+

代码测试:

+
1
2
3
4
if __name__ == "__main__":
print(Solution().jumpFloor(3))

>>> 4
+

JZ10 矩形覆盖

题目描述:

+
+

我们可以用21的小矩形横着或者竖着去覆盖更大的矩形。请问用n个21的小矩形无重叠地覆盖一个2*n的大矩形,总共有多少种方法?

+
+

解法思路:

+
1
2
3
4
5
6
7
8
9
10
11
12
class Solution:
def rectCover(self, number):
# write code here
if number <= 2:
return number

res, counter = 1, 0
for i in range(1, number + 1):
res = res + counter
counter = res - counter

return res
+

代码测试:

+
1
2
3
4
if __name__ == "__main__":
print(Solution().rectCover(4))

>>> 5
+ +

JZ21 栈的压入、弹出序列

题目描述:

+
+

输入两个整数序列,第一个序列表示栈的压入顺序,请判断第二个序列是否可能为该栈的弹出顺序。假设压入栈的所有数字均不相等。
例如序列1,2,3,4,5是某栈的压入顺序,序列4,5,3,2,1是该压栈序列对应的一个弹出序列,但4,3,5,1,2就不可能是该压栈序列的弹出序列。
(注意:这两个序列的长度是相等的)

+
+

解法思路:

+
1
2
3
4
class Solution:
def IsPopOrder(self, pushV, popV):
# write code here
pass
+ +

代码测试:

+ + +
+ +
+
+ + + + + + +
+
+
剑指offer 第五天
+
https://crisescode.github.io/blog/2020/07/13/剑指offer-第五天/
+
+
+ +
+
作者
+
Crise
+
+ + +
+
发布于
+
2020年7月13日
+
+ + + +
+
许可协议
+
+ + + + + + + + + + +
+
+ +
+
+
+ + + + +
+ + +
+ +
+ + +
+ +
+
+ + + + +
+ + +
+ + +
+
+
+
+ +
+ + + + +
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git "a/2020/07/13/\345\211\221\346\214\207offer-\347\254\254\345\205\255\345\244\251/index.html" "b/2020/07/13/\345\211\221\346\214\207offer-\347\254\254\345\205\255\345\244\251/index.html" new file mode 100644 index 0000000..98fad20 --- /dev/null +++ "b/2020/07/13/\345\211\221\346\214\207offer-\347\254\254\345\205\255\345\244\251/index.html" @@ -0,0 +1,823 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 剑指offer 第六天 - LuckyCrise + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ + + + + + +
+ +
+ +
+ + + +
+
+
+ + +
+ +
+
+
+
+ +

剑指offer 第六天

+ + +
+ +

JZ6 旋转数组的最小数字

题目描述:

+
+

把一个数组最开始的若干个元素搬到数组的末尾,我们称之为数组的旋转。
输入一个非递减排序的数组的一个旋转,输出旋转数组的最小元素。
例如数组{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
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
class Solution:
def minNumberInRotateArray(self, rotateArray):
# write code here
if len(rotateArray) == 0:
return 0
left = 0
right = len(rotateArray) - 1
while left < right:
if rotateArray[left] < rotateArray[right]:
return rotateArray[left]

mid = (left + right) // 2
if rotateArray[mid] > rotateArray[left]:
left = mid + 1
elif rotateArray[mid] < rotateArray[right]:
right = mid
else:
left += 1

return rotateArray[left]
+

代码测试:

+
1
2
3
4
5
if __name__ == "__main__":
print(Solution().minNumberInRotateArray([1, 0, 1, 1, 1]))

>>> 0

+ +

JZ18 二叉树的镜像

题目描述:

+
+

操作给定的二叉树,将其变换为源二叉树的镜像。
二叉树的镜像定义如下:

+
+
 源二叉树
+    8
+   /  \
+  6   10
+ / \  / \
+5  7 9 11
+
+镜像二叉树
+     8
+   /  \
+  10   6
+ / \  / \
+11 9 7  5

解法思路:

+
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
class TreeNode:
def __init__(self, x):
self.val = x
self.left = None
self.right = None


class Solution:
# 返回镜像树的根节点
def Mirror(self, root):
# write code here
if root is None:
return

root.left, root.right = \
self.Mirror(root.right), self.Mirror(root.left)

return root

def preOrder(self, root):
if root is None:
return

print(root.val, end=' ')
self.preOrder(root.left)
self.preOrder(root.right)
+

代码测试:

+
1
2
3
4
5
6
7
8
9
10
11
12
13
if __name__ == "__main__":
tree1 = TreeNode(8)
tree1.left = TreeNode(6)
tree1.right = TreeNode(10)
tree1.left.left = TreeNode(5)
tree1.left.right = TreeNode(7)
tree1.right.left = TreeNode(9)
tree1.right.right = TreeNode(11)

invert_tree = Solution().Mirror(tree1)
print(Solution().preOrder(invert_tree))

>>> 8 10 11 9 6 7 5 None
+

JZ23 二叉搜索树的后序遍历

题目描述:

+
+

输入一个整数数组,判断该数组是不是某二叉搜索树的后序遍历的结果。如果是则输出Yes,否则输出No。假设输入的数组的任意两个数字都互不相同。

+
+

解法思路:

+
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
class Solution:
def VerifySquenceOfBST(self, sequence):
# write code here
if len(sequence) == 0:
return False

root = sequence[-1]
for index, value in enumerate(sequence):
if value > root:
break

for value in sequence[index: -1]:
if value < root:
return False

left = True
if index > 0:
left = self.VerifySquenceOfBST(sequence[:index])

right = True
if index < len(sequence) - 1:
right = self.VerifySquenceOfBST(sequence[index: -1])

return left and right
+

代码测试:

+
1
2
3
4
5
if __name__ == "__main__":
is_binary_tree = [1, 3, 5, 9, 12, 10, 7]
print(Solution().VerifySquenceOfBST(is_binary_tree))

>>> True
+ +

JZ67 剪绳子

题目描述:

+
+

给你一根长度为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

+
+

解法思路:

+

代码测试:

+ + +
+ +
+
+ + + + + + +
+
+
剑指offer 第六天
+
https://crisescode.github.io/blog/2020/07/13/剑指offer-第六天/
+
+
+ +
+
作者
+
Crise
+
+ + +
+
发布于
+
2020年7月13日
+
+ + + +
+
许可协议
+
+ + + + + + + + + + +
+
+ +
+
+
+ + + + +
+ + +
+ +
+ + +
+ +
+
+ + + + +
+ + +
+ + +
+
+
+
+ +
+ + + + +
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git "a/2020/07/19/\345\211\221\346\214\207offer-\347\254\254\344\270\203\345\244\251/index.html" "b/2020/07/19/\345\211\221\346\214\207offer-\347\254\254\344\270\203\345\244\251/index.html" new file mode 100644 index 0000000..d5bc687 --- /dev/null +++ "b/2020/07/19/\345\211\221\346\214\207offer-\347\254\254\344\270\203\345\244\251/index.html" @@ -0,0 +1,790 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 剑指offer 第七天 - LuckyCrise + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ + + + + + +
+ +
+ +
+ + + +
+
+
+ + +
+ +
+
+
+
+ +

剑指offer 第七天

+ + +
+ +

JZ19 顺时针打印矩阵

题目描述:

+
+

输入一个矩阵,按照从外向里以顺时针的顺序依次打印出每一个数字,例如,如果输入如下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
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
class Solution:
# matrix类型为二维列表,需要返回列表
def printMatrix(self, matrix):
# write code here
top = 0
bottom = len(matrix)
left = 0
right = len(matrix[0])

res = []
# 判断是否越界
while top < bottom and left < right:
# 最上面一行,需向右打印
res.extend([matrix[top][c] for c in range(left, right)])
# 最右边一行,需向下打印
res.extend([matrix[r][right - 1] for r in range(top + 1, bottom)])
# 最下面一行,需向左打印
if bottom - top > 1:
res.extend([matrix[bottom - 1][c] for c in range(right - 2, left, -1)]) # 注意需要将右边那个值去除掉
# 最左边一行,需向上打印
if right - left > 1:
res.extend([matrix[r][left] for r in range(bottom - 1, top, -1)])

top += 1
bottom -= 1
left += 1
right -= 1

return res
+

代码测试:

+
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
if __name__ == "__main__":
num = 1
matrix = [[0 for i in range(4)] for j in range(4)]
for i in range(4):
for j in range(4):
matrix[i][j] = num
num += 1

print(Solution().printMatrix(matrix))
print(Solution().printMatrix([[1, 2], [3, 4], [5, 6], [7, 8], [9, 10]]))

>>> [1, 2, 3, 4, 8, 12, 16, 15, 14, 13, 9, 5, 6, 7, 11, 10]
[1, 2, 4, 6, 8, 10, 9, 7, 5, 3]


+ +

JZ38 二叉树的深度

题目描述:

+
+

输入一棵二叉树,求该树的深度。从根结点到叶结点依次经过的结点(含根、叶结点)形成树的一条路径,最长路径的长度为树的深度。

+
+

解法思路:

+
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
class TreeNode:
def __init__(self, x):
self.val = x
self.left = None
self.right = None


class Solution:
def TreeDepth(self, pRoot):
# write code here
if not pRoot:
return 0

x = pRoot

left = self.TreeDepth(pRoot.left)
right = self.TreeDepth(pRoot.right)

return max(left, right) + 1


class Solution2:
def TreeDepth(self, pRoot):
# write code here
if pRoot is None:
return 0
q = []
depth = 0
q.append(pRoot)
while len(q): # 队列为空时说明没有下一层
length = len(q)
for i in range(length): # 遍历层的每个节点看是否有子节点有则加入
current = q.pop(0) # current为当前遍历到的层中节点,取出,注意pop(-1)为默认,这里要pop(0),取出第一个,先入先出
if current.left:
q.append(current.left)
if current.right:
q.append(current.right)
depth += 1
return depth
+

代码测试:

+
1
2
3
4
5
6
7
8
9
10
11
12
13
14
if __name__ == "__main__":
root = TreeNode(0)
root.left = TreeNode(1)
root.right = TreeNode(2)
root.left.left = TreeNode(3)
root.left.right = TreeNode(4)
root.right.left = TreeNode(5)
root.right.left.left = TreeNode(6)

print(Solution().TreeDepth(root))
print(Solution2().TreeDepth(root))

>>> 4
4
+

JZ60 把二叉树打印成多行

题目描述:

+
+

从上到下按层打印二叉树,同一层结点从左至右输出。每一层输出一行。

+
+

解法思路:

+
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
class TreeNode:
def __init__(self, x):
self.val = x
self.left = None
self.right = None


class Solution:
# 返回二维列表[[1,2],[4,5]]
def Print(self, pRoot):
# write code here
if not pRoot:
return []

node_queue = [pRoot]
res = []
while node_queue:
val = []
length = len(node_queue)
for i in range(length):
current = node_queue.pop(0)
val.append(current.val)

if current.left:
node_queue.append(current.left)
if current.right:
node_queue.append(current.right)

res.append(val)

return res
+

代码测试:

+
1
2
3
4
5
6
7
8
9
10
11
12
if __name__ == "__main__":
root = TreeNode(8)
root.left = TreeNode(6)
root.right = TreeNode(10)
root.left.left = TreeNode(5)
root.left.right = TreeNode(7)
root.right.left = TreeNode(9)
root.right.right = TreeNode(11)

print(Solution().Print(root))

>>> [[8], [6, 10], [5, 7, 9, 11]]
+ +
+ +
+
+ + + + + + +
+
+
剑指offer 第七天
+
https://crisescode.github.io/blog/2020/07/19/剑指offer-第七天/
+
+
+ +
+
作者
+
Crise
+
+ + +
+
发布于
+
2020年7月19日
+
+ + + +
+
许可协议
+
+ + + + + + + + + + +
+
+ +
+
+
+ + + + +
+ + +
+ +
+ + +
+ +
+
+ + + + +
+ + +
+ + +
+
+
+
+ +
+ + + + +
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git "a/2020/07/20/\345\211\221\346\214\207offer-\347\254\254\345\205\253\345\244\251/index.html" "b/2020/07/20/\345\211\221\346\214\207offer-\347\254\254\345\205\253\345\244\251/index.html" new file mode 100644 index 0000000..7a5c803 --- /dev/null +++ "b/2020/07/20/\345\211\221\346\214\207offer-\347\254\254\345\205\253\345\244\251/index.html" @@ -0,0 +1,802 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 剑指offer 第八天 - LuckyCrise + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ + + + + + +
+ +
+ +
+ + + +
+
+
+ + +
+ +
+
+
+
+ +

剑指offer 第八天

+ + +
+ +

JZ59 按之字形顺序打印二叉树

题目描述:

+
+

请实现一个函数按照之字形打印二叉树,即第一行按照从左到右的顺序打印,第二层按照从右至左的顺序打印,第三行按照从左到右的顺序打印,其他行以此类推。

+
+

解法思路:
这道题其实是昨天最后一道题JZ60的升级版,其实也就是层次遍历二叉树(BFS)。层次遍历思想可以参见上一道题,只是此题需要结合二叉树的深度depth进行解题。在每次需要打印的地方,当深度depth对2取余,为0则从左到右打印,为1则反转打印。

+
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
class TreeNode:
def __init__(self, x):
self.val = x
self.left = None
self.right = None


class Solution:
def Print(self, pRoot):
# write code here
if pRoot is None:
return []

depth = 0
node_queue = [pRoot]
res = []

while node_queue:
val = []
length = len(node_queue)
for i in range(length):
current = node_queue.pop(0)
val.append(current.val)

if current.left:
node_queue.append(current.left)

if current.right:
node_queue.append(current.right)

if depth % 2 == 0:
res.append(val)
else:
res.append(list(reversed(val)))

depth += 1

return res
+

代码测试:

+
1
2
3
4
5
6
7
8
9
10
11
12
if __name__ == "__main__":
root = TreeNode(0)
root.left = TreeNode(1)
root.right = TreeNode(2)
root.left.left = TreeNode(3)
root.left.right = TreeNode(4)
root.right.left = TreeNode(5)
root.right.left.left = TreeNode(6)

print(Solution().Print(root))

>>> [[0], [2, 1], [3, 4, 5], [6]]
+ +

JZ58 对称的二叉树

题目描述:

+
+

请实现一个函数,用来判断一棵二叉树是不是对称的。注意,如果一个二叉树同此二叉树的镜像是同样的,定义其为对称的。

+
+

解法思路:

+ +
1
2
3
4
5
6
7
8
9
10
11
class TreeNode:
def __init__(self, x):
self.val = x
self.left = None
self.right = None


class Solution:
def isSymmetrical(self, pRoot):
# write code here
pass
+

代码测试:

+
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
if __name__ == "__main__":
num = 1
matrix = [[0 for i in range(4)] for j in range(4)]
for i in range(4):
for j in range(4):
matrix[i][j] = num
num += 1

print(Solution().printMatrix(matrix))
print(Solution().printMatrix([[1, 2], [3, 4], [5, 6], [7, 8], [9, 10]]))

>>> [1, 2, 3, 4, 8, 12, 16, 15, 14, 13, 9, 5, 6, 7, 11, 10]
[1, 2, 4, 6, 8, 10, 9, 7, 5, 3]


+ +

JZ38 二叉树的下一个结点

题目描述:

+
+

给定一个二叉树和其中的一个结点,请找出中序遍历顺序的下一个结点并且返回。注意,树中的结点不仅包含左右子结点,同时包含指向父结点的指针。

+
+

解法思路:

+
1
2
3
4
5
6
7
8
9
10
11
class TreeNode:
def __init__(self, x):
self.val = x
self.left = None
self.right = None


class Solution:
def GetNext(self, pNode):
# write code here
pass
+

代码测试:

+
1
2
3
4
5
6
7
8
9
10
11
12
13
14
if __name__ == "__main__":
root = TreeNode(0)
root.left = TreeNode(1)
root.right = TreeNode(2)
root.left.left = TreeNode(3)
root.left.right = TreeNode(4)
root.right.left = TreeNode(5)
root.right.left.left = TreeNode(6)

print(Solution().TreeDepth(root))
print(Solution2().TreeDepth(root))

>>> 4
4
+

JZ38 平衡二叉树

题目描述:

+
+

输入一棵二叉树,判断该二叉树是否是平衡二叉树。

+
+
+

在这里,我们只需要考虑其平衡性,不需要考虑其是不是排序二叉树

+
+

解法思路:

+
1
2
3
4
5
6
7
8
9
10
11
12
class TreeNode:
def __init__(self, x):
self.val = x
self.left = None
self.right = None


class Solution:
def IsBalanced_Solution(self, pRoot):
# write code here
pass

+ +

代码测试:

+
1
2
3
4
5
6
7
8
9
10
11
12
13
14
if __name__ == "__main__":
root = TreeNode(0)
root.left = TreeNode(1)
root.right = TreeNode(2)
root.left.left = TreeNode(3)
root.left.right = TreeNode(4)
root.right.left = TreeNode(5)
root.right.left.left = TreeNode(6)

print(Solution().TreeDepth(root))
print(Solution2().TreeDepth(root))

>>> 4
4
+ +
+ +
+
+ + + + + + +
+
+
剑指offer 第八天
+
https://crisescode.github.io/blog/2020/07/20/剑指offer-第八天/
+
+
+ +
+
作者
+
Crise
+
+ + +
+
发布于
+
2020年7月20日
+
+ + + +
+
许可协议
+
+ + + + + + + + + + +
+
+ +
+
+
+ + + + +
+ + +
+ +
+ + +
+ +
+
+ + + + +
+ + +
+ + +
+
+
+
+ +
+ + + + +
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git "a/2020/07/25/\345\211\221\346\214\207offer-\347\254\254\344\271\235\345\244\251/index.html" "b/2020/07/25/\345\211\221\346\214\207offer-\347\254\254\344\271\235\345\244\251/index.html" new file mode 100644 index 0000000..6d31393 --- /dev/null +++ "b/2020/07/25/\345\211\221\346\214\207offer-\347\254\254\344\271\235\345\244\251/index.html" @@ -0,0 +1,782 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 剑指offer 第九天 - LuckyCrise + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ + + + + + +
+ +
+ +
+ + + +
+
+
+ + +
+ +
+
+
+
+ +

剑指offer 第九天

+ + +
+ +

JZ64 滑动窗口的最大值

题目描述:

+
+

给定一个数组和滑动窗口的大小,找出所有滑动窗口里数值的最大值。例如,如果输入数组{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
2
3
4
5
6
7
8
9
10
11
class Solution:
def maxInWindows(self, num, size):
# write code here
if num is None or size <= 0:
return []

max_list = []
for i in range(len(num) - size + 1):
range_ = num[i: i+size]
max_list.append(max(range_))
return max_list
+

代码测试:

+
1
2
3
4
if __name__ == "__main__":
print(Solution().maxInWindows([2, 3, 4, 2, 6, 2, 5, 1], 2))

>>> [3, 4, 4, 6, 6, 5, 5]
+ +

JZ40 数组中只出现一次的数字

题目描述:

+
+

一个整型数组里除了两个数字之外,其他的数字都出现了两次。请写程序找出这两个只出现一次的数字。

+
+

解法思路:

+ +
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
class Solution:
# 返回[a,b] 其中ab是出现一次的两个数字
def FindNumsAppearOnce(self, array):
# write code here
if array is None:
return

hash_map = {}
for num in array:
if num in hash_map:
hash_map[num] += 1
else:
hash_map[num] = 1

res = [num for num in hash_map.keys() if hash_map[num] == 1]
return res
+

代码测试:

+
1
2
3
4
5
if __name__ == "__main__":
print(Solution().FindNumsAppearOnce([2, 3, 1, 5, 1, 3, 6, 11, 6, 0, 11, 5]))

>>> [2, 0]

+ +
+ +
+
+ + + + + + +
+
+
剑指offer 第九天
+
https://crisescode.github.io/blog/2020/07/25/剑指offer-第九天/
+
+
+ +
+
作者
+
Crise
+
+ + +
+
发布于
+
2020年7月25日
+
+ + + +
+
许可协议
+
+ + + + + + + + + + +
+
+ +
+
+
+ + + + +
+ + +
+ +
+ + +
+ +
+
+ + + + +
+ + +
+ + +
+
+
+
+ +
+ + + + +
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git "a/2020/07/27/\345\211\221\346\214\207offer-\347\254\254\345\215\201\345\244\251/index.html" "b/2020/07/27/\345\211\221\346\214\207offer-\347\254\254\345\215\201\345\244\251/index.html" new file mode 100644 index 0000000..0af0769 --- /dev/null +++ "b/2020/07/27/\345\211\221\346\214\207offer-\347\254\254\345\215\201\345\244\251/index.html" @@ -0,0 +1,799 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 剑指offer 第十天 - LuckyCrise + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ + + + + + +
+ +
+ +
+ + + +
+
+
+ + +
+ +
+
+
+
+ +

剑指offer 第十天

+ + +
+ +

JZ29 最小的K个数

题目描述:

+
+

输入n个整数,找出其中最小的K个数。例如输入4,5,1,6,2,7,3,8这8个数字,则最小的4个数字是1,2,3,4。

+
+

解法思路:
这题第一印象是直接将列表从小到大进行排序然后返回前K个数即可。所以本题第一种方法就是利用快排然后返回前K个数得到结果,这个方法没什么好说的,只要对快排熟悉即可。

+
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
def GetLeastNumbers_Solution(self, tinput, k):
# write code here
if tinput == [] or k <= 0 or k > len(tinput):
return []

return self.quick_sort(tinput)[:k]

def quick_sort(self, array):
if len(array) <= 1:
return array

pivot = array[0]
less_pivot = [num for num in array if num < pivot]
more_pivot = [num for num in array if num > pivot]

return self.quick_sort(less_pivot) + [pivot] + self.quick_sort(more_pivot)
+

代码测试:

+
1
2
3
4
5
if __name__ == "__main__":
array = [4, 5, 1, 6, 2, 7, 3, 8]
print(Solution().GetLeastNumbers_Solution(array, 4))

>>> [1, 2, 3, 4]
+ +

JZ28 数组中出现次数超过一半的数字

题目描述:

+
+

数组中有一个数字出现的次数超过数组长度的一半,请找出这个数字。例如输入一个长度为9的数组{1,2,3,2,2,2,5,4,2}。
由于数字2在数组中出现了5次,超过数组长度的一半,因此输出2。如果不存在则输出0。

+
+

解法思路:
很朴素的做法,利用哈希进行统计出数字出现的次数,然后再与数组的长度的一半进行比较即可得到结果。

+
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
class Solution:
def MoreThanHalfNum_Solution(self, numbers):
# write code here
if len(numbers) == 0:
return 0

length = len(numbers)
hash_map = {}
for num in numbers:
if num in hash_map:
hash_map[num] += 1
else:
hash_map[num] = 1
nums = [num for num in hash_map.keys() if hash_map[num] > length / 2]
return nums[0] if nums else 0
+

代码测试:

+
1
2
3
4
5
6
if __name__ == "__main__":
numbers = [1, 2, 3, 2, 2, 2, 5, 4, 2]
print(Solution().MoreThanHalfNum_Solution(numbers))

>>> 2

+ +

JZ30 连续子数组的最大和

题目描述:

+
+

HZ偶尔会拿些专业问题来忽悠那些非计算机专业的同学。今天测试组开完会后,他又发话了:在古老的一维模式识别中,常常需要计算连续子向量的最大和,
当向量全为正数的时候,问题很好解决。但是,如果向量中包含负数,是否应该包含某个负数,并期望旁边的正数会弥补它呢?
例如:{6,-3,-2,7,-15,1,2,2},连续子向量的最大和为8(从第0个开始,到第3个为止)。给一个数组,返回它的最大连续子序列的和,
你会不会被他忽悠住?(子向量的长度至少是1)

+
+

解法思路:
动态规划方法。

+
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
class Solution:
def FindGreatestSumOfSubArray(self, array):
# write code here
if len(array) == 0:
return 0

max_num = array[0]
continuous_sum = 0
for num in array:
if continuous_sum > 0:
continuous_sum += num
else:
continuous_sum = num
max_num = max(continuous_sum, max_num)

return max_num
+

代码测试:

+
1
2
3
4
5
if __name__ == "__main__":
array = [6, -3, -2, 7, -15, 1, 2, 2]
print(Solution().FindGreatestSumOfSubArray(array))

>>> 8
+

JZ50 数组中重复的数字

题目描述:

+
+

在一个长度为n的数组里的所有数字都在0到n-1的范围内。 数组中某些数字是重复的,但不知道有几个数字是重复的。也不知道每个数字重复几次。
请找出数组中任意一个重复的数字。 例如,如果输入长度为7的数组{2,3,1,0,2,5,3},那么对应的输出是第一个重复的数字2。

+
+

解法思路:

+
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
class Solution:
# 这里要特别注意~找到任意重复的一个值并赋值到duplication[0]
# 函数返回True/False
def duplicate(self, numbers, duplication):
# write code here
if len(numbers) == 0:
return False, 0
stack = []
for num in numbers:
if num > len(numbers) - 1:
return False, 0
if num not in stack:
stack.append(num)
else:
duplication.append(num)
return True, duplication[0]

return False
+ +

代码测试:

+
1
2
3
4
5
6
if __name__ == "__main__":
# numbers = [2, 3, 1, 0, 2, 5, 3]
numbers = [2, 1, 3, 1, 4]
print(Solution().duplicate(numbers, []))

>>> (True, 1)
+ + +
+ +
+
+ + + + + + +
+
+
剑指offer 第十天
+
https://crisescode.github.io/blog/2020/07/27/剑指offer-第十天/
+
+
+ +
+
作者
+
Crise
+
+ + +
+
发布于
+
2020年7月27日
+
+ + + +
+
许可协议
+
+ + + + + + + + + + +
+
+ +
+
+
+ + + + +
+ + +
+ +
+ + +
+ +
+
+ + + + +
+ + +
+ + +
+
+
+
+ +
+ + + + +
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git "a/2020/07/29/\345\211\221\346\214\207offer-\347\254\254\345\215\201\344\270\200\345\244\251/index.html" "b/2020/07/29/\345\211\221\346\214\207offer-\347\254\254\345\215\201\344\270\200\345\244\251/index.html" new file mode 100644 index 0000000..9803402 --- /dev/null +++ "b/2020/07/29/\345\211\221\346\214\207offer-\347\254\254\345\215\201\344\270\200\345\244\251/index.html" @@ -0,0 +1,764 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 剑指offer 第十一天 - LuckyCrise + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ + + + + + +
+ +
+ +
+ + + +
+
+
+ + +
+ +
+
+
+
+ +

剑指offer 第十一天

+ + +
+ + + +
+ +
+
+ + + + + + +
+
+
剑指offer 第十一天
+
https://crisescode.github.io/blog/2020/07/29/剑指offer-第十一天/
+
+
+ +
+
作者
+
Crise
+
+ + +
+
发布于
+
2020年7月29日
+
+ + + +
+
许可协议
+
+ + + + + + + + + + +
+
+ +
+
+
+ + + + +
+ + +
+ +
+ + +
+ +
+
+ + + + +
+ + +
+ + +
+
+
+
+ +
+ + + + +
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git "a/2020/07/31/\345\210\206\345\270\203\345\274\217\350\256\255\347\273\203\344\271\213PyTorch/index.html" "b/2020/07/31/\345\210\206\345\270\203\345\274\217\350\256\255\347\273\203\344\271\213PyTorch/index.html" new file mode 100644 index 0000000..129da3c --- /dev/null +++ "b/2020/07/31/\345\210\206\345\270\203\345\274\217\350\256\255\347\273\203\344\271\213PyTorch/index.html" @@ -0,0 +1,768 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 分布式训练之PyTorch - LuckyCrise + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ + + + + + +
+ +
+ +
+ + + +
+
+
+ + +
+ +
+
+
+
+ +

分布式训练之PyTorch

+ + +
+ +

由于近期来自客户需求,需要部门开发的AI平台支持上 PyTorch 框架的分布式训练,因此自己也是花了大概一周的时间,仔细研究了下 PyTorch 的分布式训练,中间也遇到了不少问题,好在通过查阅相关资料大都解决了,昨天也到客户那已经部署成功了。现将关于 PyTorch 分布式训练知识总结一下,方便大家或自己以后查阅,以下内容如有总结不到位的地方,请大家不吝赐教~

+

Overview

+ +
+ +
+
+ + + + + + +
+
+
分布式训练之PyTorch
+
https://crisescode.github.io/blog/2020/07/31/分布式训练之PyTorch/
+
+
+ +
+
作者
+
Crise
+
+ + +
+
发布于
+
2020年7月31日
+
+ + + +
+
许可协议
+
+ + + + + + + + + + +
+
+ +
+
+
+ + + + +
+ + +
+ +
+ + +
+ +
+
+ + + + +
+ + +
+ + +
+
+
+
+ +
+ + + + +
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git "a/2020/08/08/NLP-\346\226\207\346\234\254\346\221\230\350\246\201\344\271\213PGN\346\214\207\351\222\210\347\224\237\346\210\220\347\275\221\347\273\234/index.html" "b/2020/08/08/NLP-\346\226\207\346\234\254\346\221\230\350\246\201\344\271\213PGN\346\214\207\351\222\210\347\224\237\346\210\220\347\275\221\347\273\234/index.html" new file mode 100644 index 0000000..915788b --- /dev/null +++ "b/2020/08/08/NLP-\346\226\207\346\234\254\346\221\230\350\246\201\344\271\213PGN\346\214\207\351\222\210\347\224\237\346\210\220\347\275\221\347\273\234/index.html" @@ -0,0 +1,771 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + [NLP] 文本摘要之PGN指针生成网络 - LuckyCrise + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ + + + + + +
+ +
+ +
+ + + +
+
+
+ + +
+ +
+
+
+
+ +

[NLP] 文本摘要之PGN指针生成网络

+ + +
+ + + +
+ +
+
+ + + + + + +
+
+
[NLP] 文本摘要之PGN指针生成网络
+
https://crisescode.github.io/blog/2020/08/08/NLP-文本摘要之PGN指针生成网络/
+
+
+ +
+
作者
+
Crise
+
+ + +
+
发布于
+
2020年8月8日
+
+ + + +
+
许可协议
+
+ + + + + + + + + + +
+
+ +
+
+
+ + + + +
+ + +
+ +
+ + +
+ +
+
+ + + + +
+ + +
+ + +
+
+
+
+ +
+ + + + +
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git "a/2020/08/31/NLP-\346\250\241\345\236\213\351\203\250\347\275\262\345\256\236\350\267\265\357\274\2101\357\274\211Gunicorn-Falcon-Model/index.html" "b/2020/08/31/NLP-\346\250\241\345\236\213\351\203\250\347\275\262\345\256\236\350\267\265\357\274\2101\357\274\211Gunicorn-Falcon-Model/index.html" new file mode 100644 index 0000000..abc54aa --- /dev/null +++ "b/2020/08/31/NLP-\346\250\241\345\236\213\351\203\250\347\275\262\345\256\236\350\267\265\357\274\2101\357\274\211Gunicorn-Falcon-Model/index.html" @@ -0,0 +1,771 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + [AI] 模型部署实践(1)Gunicorn + Falcon + Model - LuckyCrise + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ + + + + + +
+ +
+ +
+ + + +
+
+
+ + +
+ +
+
+
+
+ +

[AI] 模型部署实践(1)Gunicorn + Falcon + Model

+ + +
+ + + +
+ +
+
+ + + + + + +
+
+
[AI] 模型部署实践(1)Gunicorn + Falcon + Model
+
https://crisescode.github.io/blog/2020/08/31/NLP-模型部署实践(1)Gunicorn-Falcon-Model/
+
+
+ +
+
作者
+
Crise
+
+ + +
+
发布于
+
2020年8月31日
+
+ + + +
+
许可协议
+
+ + + + + + + + + + +
+
+ +
+
+
+ + + + +
+ + +
+ +
+ + +
+ +
+
+ + + + +
+ + +
+ + +
+
+
+
+ +
+ + + + +
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git "a/2020/09/29/AI-\346\250\241\345\236\213\351\203\250\347\275\262\345\256\236\350\267\265\357\274\2102\357\274\211Tensorflow-Serving\351\203\250\347\275\262\346\226\271\345\274\217/index.html" "b/2020/09/29/AI-\346\250\241\345\236\213\351\203\250\347\275\262\345\256\236\350\267\265\357\274\2102\357\274\211Tensorflow-Serving\351\203\250\347\275\262\346\226\271\345\274\217/index.html" new file mode 100644 index 0000000..0c90613 --- /dev/null +++ "b/2020/09/29/AI-\346\250\241\345\236\213\351\203\250\347\275\262\345\256\236\350\267\265\357\274\2102\357\274\211Tensorflow-Serving\351\203\250\347\275\262\346\226\271\345\274\217/index.html" @@ -0,0 +1,771 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + [AI] 模型部署实践(2)Tensorflow Serving 部署方式 - LuckyCrise + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ + + + + + +
+ +
+ +
+ + + +
+
+
+ + +
+ +
+
+
+
+ +

[AI] 模型部署实践(2)Tensorflow Serving 部署方式

+ + +
+ + + +
+ +
+
+ + + + + + +
+
+
[AI] 模型部署实践(2)Tensorflow Serving 部署方式
+
https://crisescode.github.io/blog/2020/09/29/AI-模型部署实践(2)Tensorflow-Serving部署方式/
+
+
+ +
+
作者
+
Crise
+
+ + +
+
发布于
+
2020年9月29日
+
+ + + +
+
许可协议
+
+ + + + + + + + + + +
+
+ +
+
+
+ + + + +
+ + +
+ +
+ + +
+ +
+
+ + + + +
+ + +
+ + +
+
+
+
+ +
+ + + + +
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git "a/2020/09/29/Kubernetes-\345\237\272\344\272\216kubeadm\346\220\255\345\273\272\344\270\200\344\270\252\345\256\214\346\225\264\347\232\204Kubernetes\351\233\206\347\276\244/index.html" "b/2020/09/29/Kubernetes-\345\237\272\344\272\216kubeadm\346\220\255\345\273\272\344\270\200\344\270\252\345\256\214\346\225\264\347\232\204Kubernetes\351\233\206\347\276\244/index.html" new file mode 100644 index 0000000..618478f --- /dev/null +++ "b/2020/09/29/Kubernetes-\345\237\272\344\272\216kubeadm\346\220\255\345\273\272\344\270\200\344\270\252\345\256\214\346\225\264\347\232\204Kubernetes\351\233\206\347\276\244/index.html" @@ -0,0 +1,851 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + [Kubernetes] 基于kubeadm搭建一个完整的Kubernetes集群 - LuckyCrise + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ + + + + + +
+ +
+ +
+ + + +
+
+
+ + +
+ +
+
+
+
+ +

[Kubernetes] 基于kubeadm搭建一个完整的Kubernetes集群

+ + +
+ +

Overview

Kubernetes 是一个可移植的、可扩展的开源平台,用于管理容器化的工作负载和服务,可促进声明式配置和自动化。Kubernetes 拥有一个庞大且快速增长的生态系统。Kubernetes 是 Google 于 2014 年 6 月基于其内部使用的 Borg 系统开源出来的容器编排调度引擎,Google 将其作为初始和核心项目贡献给 CNCF(云原生计算基金会),近年来逐渐发展出了云原生生态。

+

Kubernetes 的目标不仅仅是一个编排系统,而是提供一个规范用以描述集群的架构,定义服务的最终状态,使系统自动地达到和维持该状态。Kubernetes 作为云原生应用的基石,相当于一个云操作系统,其重要性不言而喻。

+ + +

为什么需要 Kubernetes,它能做什么?

容器是打包和运行应用程序的好方式。在生产环境中,您需要管理运行应用程序的容器,并确保不会停机。例如,如果一个容器发生故障,则需要启动另一个容器。如果系统处理此行为,会不会更容易?

+

这就是 Kubernetes 的救援方法!Kubernetes 为您提供了一个可弹性运行分布式系统的框架。Kubernetes 会满足您的扩展要求、故障转移、部署模式等。例如,Kubernetes 可以轻松管理系统的 Canary 部署。

+

Kubernetes 能够提供以下一些功能:

+
    +
  • 服务发现和负载均衡
    Kubernetes 可以使用 DNS 名称或自己的 IP 地址公开容器,如果到容器的流量很大, Kubernetes 可以负载均衡并分配网络流量,从而使部署稳定。
  • +
  • 存储编排
    Kubernetes 允许您自动挂载您选择的存储系统,例如本地存储、公共云提供商等。
  • +
  • 自动部署和回滚
    您可以使用 Kubernetes 描述已部署容器的所需状态,它可以以受控的速率将实际状态更改为所需状态。例如,您可以自动化 Kubernetes 来为您的部署创建新容器,删除现有容器并将它们的所有资源用于新容器。
  • +
  • 自动二进制打包
    Kubernetes 允许您指定每个容器所需 CPU 和内存(RAM)。当容器指定了资源请求时,Kubernetes 可以做出更好的决策来管理容器的资源。
  • +
  • 自我修复
    Kubernetes 重新启动失败的容器、替换容器、杀死不响应用户定义的运行状况检查的容器,并且在准备好服务之前不将其通告给客户端。
  • +
  • 密钥与配置管理
    Kubernetes 允许您存储和管理敏感信息,例如密码、OAuth 令牌和 ssh 密钥。您可以在不重建容器镜像的情况下部署和更新密钥和应用程序配置,也无需在堆栈配置中暴露密钥。
  • +
+

因此综上,我们需要好好学习 Kubernetes 这个强大的云操作系统,增强自身的竞争力。工欲善其事,必先利其器,本篇也是 Kubernetes 系列的第一篇博文,讲述如何利用 Kubeadm 这个工具来搭建一套供自己学习的 Kubernetes 集群。

+

Kubeadm 到底是什么?

Kubeadm 能够用以创建一个符合最佳实践的最小化 Kubernetes 集群。事实上,你可以使用 kubeadm 配置一个通过 Kubernetes 一致性测试的集群。 kubeadm 还支持其他集群生命周期功能, 例如:启动引导令牌和集群升级。

+

kubeadm 工具很棒,如果你需要:

+
    +
  • 一个尝试 Kubernetes 的简单方法。
  • +
  • 一个现有用户可以自动设置集群并测试其应用程序的途径。
  • +
  • 其他具有更大范围的生态系统和/或安装工具中的构建模块。
  • +
+

你可以在各种机器上安装和使用 kubeadm:笔记本电脑, 一组云服务器,Raspberry Pi 等。无论是部署到云还是本地,你都可以将 kubeadm 集成到预配置系统中,例如 Ansible 或 Terraform。

+

准备工作

    +
  • 一台或多台运行着下列系统的机器,去阿里云申请或者自己物理机用 VMvare 新建都行:
      +
    • Ubuntu 16.04+
    • +
    • Debian 9+
    • +
    • CentOS 7
    • +
    • Red Hat Enterprise Linux (RHEL) 7
    • +
    • Fedora 25+
    • +
    • HypriotOS v1.0.1+
    • +
    • Container Linux (测试 1800.6.0 版本)
    • +
    +
  • +
  • 单机可用资源建议 2 核 CPU、8 GB 内存或以上,再小的话问题也不大,但是能调度的 Pod 数量就比较有限了
  • +
  • 每台机器能够访问外网,因为需要拉取镜像
  • +
  • 集群中所有计算机之间具有完全的网络连接
  • +
+

安装 Kubeadm 以及 Docker

上述介绍过 kubeadm 的基础用法,接下来我将会介绍基于 Centos 8 安装 Kubernetes 组件以及 Docker。

+

配置安装源

    +
  • 配置docker
    1
    $ wget https://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo -O /etc/yum.repos.d/docker-ce.repo
  • +
  • 配置kubernetes
    1
    2
    3
    4
    5
    6
    7
    8
    9
    $ cat > /etc/yum.repos.d/kubernetes.repo << EOF
    [kubernetes]
    name=Kubernetes
    baseurl=https://mirrors.aliyun.com/kubernetes/yum/repos/kubernetes-el7-x86_64
    enabled=1
    gpgcheck=0
    repo_gpgcheck=0
    gpgkey=https://mirrors.aliyun.com/kubernetes/yum/doc/yum-key.gpg https://mirrors.aliyun.com/kubernetes/yum/doc/rpm-package-key.gpg
    EOF
  • +
  • 本地缓存
    1
    $ dnf makecache
    + +
  • +
+

安装 Kubeadm 以及 docker

    +
  • 执行以下命令:
    1
    2
    3
    4
    $ dnf -y install docker-ce
    $ systemctl enable docker
    $ systemctl start docker
    $ dnf install -y kubelet-1.18.0 kubeadm-1.18.0 kubectl-1.18.0
    + +
  • +
+

这里安装了 Docker 公司发布的最新的 Docker CE(社区版),Kubernetes 相关的组件安装的 1.18.0 版本,基本是目前为止最新的版本了。

+

部署 Kubernetes 的 Master 节点

利用 kubeadm 可以很简单的来初始化 kubernetes 集群的 master 节点,执行以下命令:

+
1
2
3
4
5
6
7
8
9
10
11
12
13
kubeadm init \
--apiserver-advertise-address=192.168.0.2 \
--kubernetes-version v1.18.0 \
--service-cidr=10.1.0.0/16 \
--pod-network-cidr=10.244.0.0/16

If you can't access foreign websites:
kubeadm init \
--apiserver-advertise-address=192.168.0.2 \
--image-repository registry.aliyuncs.com/google_containers \
--kubernetes-version v1.18.0 \
--service-cidr=10.1.0.0/16 \
--pod-network-cidr=10.244.0.0/16
+

上述命令行参数解释:

+
    +
  • --apiserver-advertise-address:可用于为控制平面节点的 API server 设置广播地址,
  • +
+

部署网络插件

在 Kubernetes 项目“一切皆容器”的设计理念指导下,部署网络插件也是通过启动pod的形式来配置网络,其中有两种网络插件可供部署:

+
    +
  • 部署 flannel 网络插件(详细介绍后面会在开一篇博文):
    1
    2
    $ kubectl apply -f https://raw.githubusercontent.com/coreos/flannel/a70459be0084506e4ec919aa1c114638878db11b/Documentation/kube-flannel.yml
    update: https://raw.githubusercontent.com/coreos/flannel/v0.12.0/Documentation/kube-flannel.yml
  • +
  • 部署 calico 网络插件:
    1
    $ kubectl apply -f https://docs.projectcalico.org/v3.14/manifests/calico.yaml
    +上述两个网络插件只需部署一个即可,部署成功与否可通过查看对应 pod 的运行状态即可:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    $ kubectl get pods -n kube-system
    NAME READY STATUS RESTARTS AGE
    calico-kube-controllers-65f8bc95db-ngv7v 1/1 Running 0 3d19h
    calico-node-9sr5c 1/1 Running 0 3d19h
    calico-node-jtt5w 1/1 Running 0 3d19h
    coredns-7ff77c879f-v645l 1/1 Running 0 3d19h
    coredns-7ff77c879f-vdrcf 1/1 Running 0 3d19h
    etcd-master 1/1 Running 1 3d20h
    kube-apiserver-master 1/1 Running 1 3d20h
    kube-controller-manager-master 1/1 Running 1 3d20h
    kube-proxy-sbxzb 1/1 Running 0 3d19h
    kube-proxy-xfw7t 1/1 Running 0 3d19h
    kube-scheduler-master 1/1 Running 1 3d20h
    + +
  • +
+

可以看到,所有的系统 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 的计算节点

Kubernetes 的 计算节点跟 Master 节点几乎是相同的,它们运行着的都是一个 kubelet 组件。唯一的区别在于,在 kubeadm init 的过程中,kubelet 启动后,Master 节点上还会自动运行 kube-apiserver、kube-scheduler、kube-controller-manger 这三个系统 Pod。
执行以下命令:

+
1
2
$ kubeadm join 192.168.56.12:6443 --token japatq.5vib0jhpgmeeqsb2 \
--discovery-token-ca-cert-hash sha256:c08f2729dbe9e2b1ce9f44e6d3159c493cc686b2e93dc252f7658cb26b87d726
+

用以加入192.168.56.12这个 IP 的计算节点到集群中,以上Token可用kubeclt token list得到。

+

通过执行以上步骤便可以搭建好一个网络完整的 Kubernetes 集群。当然,也可以继续往集群中添加其他的插件,比如部署 Dashboard 可视化插件,部署容器存储插件等等。这个就因人而异了,留给大家自由发挥了…

+

测试集群

    +
  • 列出集群的节点
    1
    2
    3
    4
    [root@master ~]# kubectl get nodes
    NAME STATUS ROLES AGE VERSION
    master Ready master 33d v1.18.0
    node Ready <none> 33d v1.18.0
  • +
  • 列出系统的pod资源
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    [root@master ~]# kubectl get pod -n kube-system
    NAME READY STATUS RESTARTS AGE
    calico-kube-controllers-65f8bc95db-ngv7v 1/1 Running 0 33d
    calico-node-9sr5c 1/1 Running 0 33d
    calico-node-jtt5w 1/1 Running 0 33d
    coredns-7ff77c879f-v645l 1/1 Running 0 33d
    coredns-7ff77c879f-vdrcf 1/1 Running 0 33d
    etcd-master 1/1 Running 1 33d
    kube-apiserver-master 1/1 Running 1 33d
    kube-controller-manager-master 1/1 Running 1 33d
    kube-proxy-sbxzb 1/1 Running 0 33d
    kube-proxy-xfw7t 1/1 Running 0 33d
    kube-scheduler-master 1/1 Running 1 33d
    + +
  • +
+

参考

+ + +
+ +
+
+ + + + + + +
+
+
[Kubernetes] 基于kubeadm搭建一个完整的Kubernetes集群
+
https://crisescode.github.io/blog/2020/09/29/Kubernetes-基于kubeadm搭建一个完整的Kubernetes集群/
+
+
+ +
+
作者
+
Crise
+
+ + +
+
发布于
+
2020年9月29日
+
+ + + +
+
许可协议
+
+ + + + + + + + + + +
+
+ +
+
+
+ + + + +
+ + +
+ +
+ + +
+ +
+
+ + + + +
+ + +
+ + +
+
+
+
+ +
+ + + + +
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git "a/2020/10/18/LeetCode-\346\225\260\346\215\256\347\273\223\346\236\204\344\271\213\346\240\221/index.html" "b/2020/10/18/LeetCode-\346\225\260\346\215\256\347\273\223\346\236\204\344\271\213\346\240\221/index.html" new file mode 100644 index 0000000..1c6e6e6 --- /dev/null +++ "b/2020/10/18/LeetCode-\346\225\260\346\215\256\347\273\223\346\236\204\344\271\213\346\240\221/index.html" @@ -0,0 +1,771 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + [LeetCode] 数据结构之树 - LuckyCrise + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ + + + + + +
+ +
+ +
+ + + +
+
+
+ + +
+ +
+
+
+
+ +

[LeetCode] 数据结构之树

+ + +
+ + + +
+ +
+
+ + + + + + +
+
+
[LeetCode] 数据结构之树
+
https://crisescode.github.io/blog/2020/10/18/LeetCode-数据结构之树/
+
+
+ +
+
作者
+
Crise
+
+ + +
+
发布于
+
2020年10月18日
+
+ + + +
+
许可协议
+
+ + + + + + + + + + +
+
+ +
+
+
+ + + + +
+ + +
+ +
+ + +
+ +
+
+ + + + +
+ + +
+ + +
+
+
+
+ +
+ + + + +
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git "a/2020/10/29/Kubernetes-\350\256\244\350\257\206\344\270\200\344\270\213Kubernetes/index.html" "b/2020/10/29/Kubernetes-\350\256\244\350\257\206\344\270\200\344\270\213Kubernetes/index.html" new file mode 100644 index 0000000..67543f1 --- /dev/null +++ "b/2020/10/29/Kubernetes-\350\256\244\350\257\206\344\270\200\344\270\213Kubernetes/index.html" @@ -0,0 +1,838 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + [Kubernetes] 认识一下Kubernetes - LuckyCrise + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ + + + + + +
+ +
+ +
+ + + +
+
+
+ + +
+ +
+
+
+
+ +

[Kubernetes] 认识一下Kubernetes

+ + +
+ +

有哪些组件

Kubernetes 集群分为两个部分:

+
    +
  • Kubernetes 控制平面
  • +
  • (工作)节点
  • +
+

其中控制平面的组件有:

+
    +
  • Etcd 分布式持久化存储
  • +
  • API Server
  • +
  • Kube Scheduler
  • +
  • Kube Controller
  • +
+

运行容器任务依赖于每个工作节点上运行的组件,包括:

+
    +
  • Kubelet
  • +
  • Kubelet 服务代理(kube proxy)
  • +
  • 容器运行时(docker,rkt,containerd或者其他)
  • +
+ + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git "a/2020/12/26/GO-\342\200\224-Golang\345\255\246\344\271\240\344\271\213interface\346\216\245\345\217\243/index.html" "b/2020/12/26/GO-\342\200\224-Golang\345\255\246\344\271\240\344\271\213interface\346\216\245\345\217\243/index.html" new file mode 100644 index 0000000..4f0d2f2 --- /dev/null +++ "b/2020/12/26/GO-\342\200\224-Golang\345\255\246\344\271\240\344\271\213interface\346\216\245\345\217\243/index.html" @@ -0,0 +1,764 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + [GO] golang学习之interface接口 - LuckyCrise + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ + + + + + +
+ +
+ +
+ + + +
+
+
+ + +
+ +
+
+
+
+ +

[GO] golang学习之interface接口

+ + +
+ + + +
+ +
+
+ + + + + + +
+
+
[GO] golang学习之interface接口
+
https://crisescode.github.io/blog/2020/12/26/GO-—-Golang学习之interface接口/
+
+
+ +
+
作者
+
Crise
+
+ + +
+
发布于
+
2020年12月26日
+
+ + + +
+
许可协议
+
+ + + + + + + + + + +
+
+ +
+
+
+ + + + +
+ + +
+ +
+ + +
+ +
+
+ + + + +
+ + +
+ + +
+
+
+
+ +
+ + + + +
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git "a/2020/12/27/GO-\342\200\224-\350\247\243\346\236\220-GOROOT\343\200\201GOPATH-\344\273\245\345\217\212-UBUNTU-\344\270\255\346\236\204\345\273\272-golang-\351\241\271\347\233\256/index.html" "b/2020/12/27/GO-\342\200\224-\350\247\243\346\236\220-GOROOT\343\200\201GOPATH-\344\273\245\345\217\212-UBUNTU-\344\270\255\346\236\204\345\273\272-golang-\351\241\271\347\233\256/index.html" new file mode 100644 index 0000000..db9631a --- /dev/null +++ "b/2020/12/27/GO-\342\200\224-\350\247\243\346\236\220-GOROOT\343\200\201GOPATH-\344\273\245\345\217\212-UBUNTU-\344\270\255\346\236\204\345\273\272-golang-\351\241\271\347\233\256/index.html" @@ -0,0 +1,767 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + [GO] — 解析 GOROOT、GOPATH 以及 ubuntu 中构建 golang 项目 - LuckyCrise + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ + + + + + +
+ +
+ +
+ + + +
+
+
+ + +
+ +
+
+
+
+ +

[GO] — 解析 GOROOT、GOPATH 以及 ubuntu 中构建 golang 项目

+ + +
+ + + +
+ +
+
+ + + + + + +
+
+
[GO] — 解析 GOROOT、GOPATH 以及 ubuntu 中构建 golang 项目
+
https://crisescode.github.io/blog/2020/12/27/GO-—-解析-GOROOT、GOPATH-以及-UBUNTU-中构建-golang-项目/
+
+
+ +
+
作者
+
Crise
+
+ + +
+
发布于
+
2020年12月27日
+
+ + + +
+
许可协议
+
+ + + + + + + + + + +
+
+ +
+
+
+ + + + +
+ + +
+ +
+ + +
+ +
+
+ + + + +
+ + +
+ + +
+
+
+
+ +
+ + + + +
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git "a/2021/01/12/2020-\345\271\264\347\273\210\346\200\273\347\273\223/index.html" "b/2021/01/12/2020-\345\271\264\347\273\210\346\200\273\347\273\223/index.html" new file mode 100644 index 0000000..c009b04 --- /dev/null +++ "b/2021/01/12/2020-\345\271\264\347\273\210\346\200\273\347\273\223/index.html" @@ -0,0 +1,741 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 2020 年终总结 - LuckyCrise + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ + + + + + +
+ +
+ +
+ + + +
+
+
+ + +
+ +
+
+
+
+ +

2020 年终总结

+ + +
+ +

一直以来自己是不喜欢将一些总结放到博客里来的,感觉这个还是挺私密的,是自己一年的发展回顾。但是看了很多大佬的博客,他们都很擅于总结自己的一年,并且也会将之发到自己的博客上,我感觉这样也挺好的。自己之前都是将这些总结放到本地存储,但这样有时写了一会就不想去写了,很容易虎头蛇尾。因此我决定以后可以将一些总结,感触什么的放到博客里,以此来监督自己一直坚持下去~

+ + +

2020,一个不平凡的一年,这整年人人都基本是带着口罩过来的,直到现在还是无法摆脱带口罩,每天出行仍需带着上地铁,进公司。在年初,因为疫情影响,相信很多人都是被困在家远程办公。刚开始在家办公,自己还是不适应的,没有公司的那种开发氛围,很多需求也不能面对面及时的沟通得以解决,这样还是挺不方便的。但是后来,随着在家办公的时间长了,感觉在家办公也不错,至少节省了上下班通勤路上的时间,每天从床上爬起来就可以投入工作,这种感觉还是挺好的。当然这样对于大多数人工作效率肯定是很低的,所以公司还是会尽量要求员工在家隔离完就需要回公司办公了,因此自己大概在今年3月份回到联想大厦办公了。

+

其实自己在年初的时候给自己的2020定了一些计划的,但是关于实现与否,还真是偏差甚远。首先是打算这一年换一份工作的,最好是NLP算法工程师相关的工作。在今年的前三个月里,自己还是很认真的在学习NLP相关的知识,但是后面发现自己还是很难去找这相关的工作,加上后面在联想又大部分时间在做开发相关的工作,所以后面也就没再学习了。关于跳槽,从今年8月份开始更新几个网站的简历,然后也是8月份开始陆续接到了很多猎头的电话,也面试了很多了公司,最终拿了几个offer,待遇什么的较联想这边也有一定的涨幅。最后选择了一家互联网+金融的公司,信也科技,但不是算法相关的岗位,不过也挺符合自己的发展方向的,目前主要是机器学习容器云平台开发,主要是
Python / Go 作为技术栈, 基于 Kubernetes / Docker 打造基于云原生上传数据集,标注,特征提取,训练以及模型部署一体化的机器学习平台。

+ + +
+ +
+
+ + + + + + +
+
+
2020 年终总结
+
https://crisescode.github.io/blog/2021/01/12/2020-年终总结/
+
+
+ +
+
作者
+
Crise
+
+ + +
+
发布于
+
2021年1月12日
+
+ + + +
+
许可协议
+
+ + + + + + + + + + +
+
+ +
+
+
+ + + + +
+ + +
+ +
+ + +
+ +
+
+ + + + +
+ + +
+ + +
+
+
+
+ +
+ + + + +
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git "a/2021/01/24/Kubernetes-Kubernetes-\344\270\255\347\232\204\345\274\271\346\200\247\344\274\270\347\274\251\344\273\245\345\217\212\350\207\252\345\212\250\346\211\251\345\256\271/index.html" "b/2021/01/24/Kubernetes-Kubernetes-\344\270\255\347\232\204\345\274\271\346\200\247\344\274\270\347\274\251\344\273\245\345\217\212\350\207\252\345\212\250\346\211\251\345\256\271/index.html" new file mode 100644 index 0000000..7f08702 --- /dev/null +++ "b/2021/01/24/Kubernetes-Kubernetes-\344\270\255\347\232\204\345\274\271\346\200\247\344\274\270\347\274\251\344\273\245\345\217\212\350\207\252\345\212\250\346\211\251\345\256\271/index.html" @@ -0,0 +1,770 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + [Kubernetes] Kubernetes 中的弹性伸缩以及自动扩容 - LuckyCrise + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ + + + + + +
+ +
+ +
+ + + +
+
+
+ + +
+ +
+
+
+
+ +

[Kubernetes] Kubernetes 中的弹性伸缩以及自动扩容

+ + +
+ + + +
+ +
+
+ + + + + + +
+
+
[Kubernetes] Kubernetes 中的弹性伸缩以及自动扩容
+
https://crisescode.github.io/blog/2021/01/24/Kubernetes-Kubernetes-中的弹性伸缩以及自动扩容/
+
+
+ +
+
作者
+
Crise
+
+ + +
+
发布于
+
2021年1月24日
+
+ + + +
+
许可协议
+
+ + + + + + + + + + +
+
+ +
+
+
+ + + + +
+ + +
+ +
+ + +
+ +
+
+ + + + +
+ + +
+ + +
+
+
+
+ +
+ + + + +
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git "a/2021/11/15/Kubernetes-Kubernetes-\346\240\270\345\277\203\347\273\204\344\273\266\344\271\213-kube-apiserver/index.html" "b/2021/11/15/Kubernetes-Kubernetes-\346\240\270\345\277\203\347\273\204\344\273\266\344\271\213-kube-apiserver/index.html" new file mode 100644 index 0000000..d838975 --- /dev/null +++ "b/2021/11/15/Kubernetes-Kubernetes-\346\240\270\345\277\203\347\273\204\344\273\266\344\271\213-kube-apiserver/index.html" @@ -0,0 +1,815 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + [Kubernetes] Kubernetes 核心组件之 kube-apiserver - LuckyCrise + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ + + + + + +
+ +
+ +
+ + + +
+
+
+ + +
+ +
+
+
+
+ +

[Kubernetes] Kubernetes 核心组件之 kube-apiserver

+ + +
+ +

kube-apiserverKubernetes 最重要的核心组件之一,主要能提供的功能如下:

+
    +
  • 给集群其他组件提供数据交互以及通信枢纽功能,以RESTful API 的形式提供其他组件查询,修改集群状态的 CURD(Create,Read,Update,Detele)接口,然后将状态储存到 etcd 中;
  • +
  • 为用户请求接入认证,授权以及准入控制等功能;
  • +
  • 并且可以用来处理乐观锁, 当有并发更新的情况, 对对象做更改就不会被其他客户端覆盖。 + +
  • +
+

如何部署

工作原理

kube-apiserver 提供了 KubernetesREST API,实现了认证、授权、准入控制等安全校验功能,同时也负责集群状态的存储操作(通过 etcd)。

+

认证

授权

准入控制

API 访问示例

kube-apiserver 提供了为每种语言提供了 SDK,方便用户访问集群其他组件,以及将数据存储或更新到etcd中,如下:

+ +

kubectl 访问

    +
  • 查询 kube-apiserver 支持API的版本

    +
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    $ kubectl api-versions
    admissionregistration.k8s.io/v1
    admissionregistration.k8s.io/v1beta1
    apiextensions.k8s.io/v1
    apiextensions.k8s.io/v1beta1
    apps/v1

    ...

    scheduling.k8s.io/v1
    scheduling.k8s.io/v1beta1
    storage.k8s.io/v1
    storage.k8s.io/v1beta1
    traefik.containo.us/v1alpha1
    v1
    xgboostjob.kubeflow.org/v1

  • +
  • 查询 kube-apiserver 支持API的资源对象

    +
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    $ kubectl api-resources
    NAME SHORTNAMES APIGROUP NAMESPACED KIND
    bindings true Binding
    componentstatuses cs false ComponentStatus
    configmaps cm true ConfigMap

    ...

    tlsoptions traefik.containo.us true TLSOption
    tlsstores traefik.containo.us true TLSStore
    traefikservices traefik.containo.us true TraefikService
    xgboostjobs xgboostjob.kubeflow.org true XGBoostJob

  • +
  • 查看 kube-apiserverv1/namepsace 信息

    +
    1
    2
    3
    $ kubectl get --raw /api/v1/namespaces
    {"kind":"NamespaceList","apiVersion":"v1","metadata":{"selfLink":"/api/v1/namespaces","resourceVersion":"190115288"},"items":[{"metadata":{"name":"airflow","selfLink":"/api/v1/namespaces/airflow","uid":"f4756c7a-8bd7-4988-a69c-c849a3c035be","resourceVersion":"79499605","creationTimestamp":"2021-05-06T07:39:19Z","managedFields":[{"manager":"kubectl-create","operation":"Update","apiVersion":"v1","time":"2021-05-06T07:39:19Z","fieldsType":"FieldsV1","fieldsV1":{"f:status":{"f:phase":{}}}}]},"spec":{"finalizers":["kubernetes"]},"status":{"phase":"Active"}},{"metadata":{"name":"crise","selfLink":"/api/v1/namespaces/crise","uid":"6f943c7a-8419-4c95-bf5a-2972f3631aab","resourceVersion":"155793497","creationTimestamp":"2021-09-26T05:09:22Z","managedFields":[{"manager":"kubectl-create","operation":"Update","apiVersion":"v1","time":"2021-09-26T05:09:22Z","fieldsType":"FieldsV1","fieldsV1":{"f:status":{"f:phase":{}}}}]},"spec":{"finalizers":["kubernetes"]},"status":{"phase":"Active"}},{"metadata":{"name":"default","selfLink":"/api/v1/namespaces/default","uid":"545db544-c735-4d06-a600-981144f245a8","resourceVersion":"157","creationTimestamp":"2020-11-12T07:25:33Z","managedFields":[{"manager":"kube-apiserver","operation":"Update","apiVersion":"v1","time":"2020-11-12T07:25:33Z","fieldsType":"FieldsV1","fieldsV1":{"f:status":{"f:phase":{}}}}]},"spec":{"finalizers":["kubernetes"]},"status":{"phase":"Active"}},{"metadata":{"name":"elastic","selfLink":"/api/v1/namespaces/elastic","uid":"adcddefd-2a71-4b65-af74-ec4d5ac854b4","resourceVersion":"132059434","creationTimestamp":"2021-08-10T08:36:48Z","labels":{"name":"elastic"},"managedFields":[{"manager":"Go-http-client","operation":"Update","apiVersion":"v1","time":"2021-08-10T08:36:48Z","fieldsType":"FieldsV1","fieldsV1":{"f:metadata":{"f:labels":{".":{},"f:name":{}}},"f:status":{"f:phase":{}}}}]},"spec":{"finalizers":["kubernetes"]},"status":{"phase":"Active"}},{"metadata":{"name":"kafka","selfLink":"/api/v1/namespaces/kafka","uid":"82f78a4a-b135-49af-a6d2-34b162deff34","resourceVersion":"126083706","creationTimestamp":"2021-07-30T06:28:47Z","labels":{"name":"kafka"},"managedFields":[{"manager":"Go-http-client","operation":"Update","apiVersion":"v1","time":"2021-07-30T06:28:47Z","fieldsType":"FieldsV1","fieldsV1":{"f:metadata":{"f:labels":{".":{},"f:name":{}}},"f:status":{"f:phase":{}}}}]},"spec":{"finalizers":["kubernetes"]},"status":{"phase":"Active"}},{"metadata":{"name":"kube-node-lease","selfLink":"/api/v1/namespaces/kube-node-lease","uid":"16073100-6a4c-4275-9cb4-914d16e92dd9","resourceVersion":"43","creationTimestamp":"2020-11-12T07:25:32Z","managedFields":[{"manager":"kube-apiserver","operation":"Update","apiVersion":"v1","time":"2020-11-12T07:25:32Z","fieldsType":"FieldsV1","fieldsV1":{"f:status":{"f:phase":{}}}}]},"spec":{"finalizers":["kubernetes"]},"status":{"phase":"Active"}},{"metadata":{"name":"kube-public","selfLink":"/api/v1/namespaces/kube-public","uid":"f6077460-b5ab-4250-ad00-bd7a32745873","resourceVersion":"41","creationTimestamp":"2020-11-12T07:25:32Z","managedFields":[{"manager":"kube-apiserver","operation":"Update","apiVersion":"v1","time":"2020-11-12T07:25:32Z","fieldsType":"FieldsV1","fieldsV1":{"f:status":{"f:phase":{}}}}]},"spec":{"finalizers":["kubernetes"]},"status":{"phase":"Active"}},{"metadata":{"name":"kube-system","selfLink":"/api/v1/namespaces/kube-system","uid":"4671dc1b-9f93-4c23-be43-65579ff03293","resourceVersion":"1051","creationTimestamp":"2020-11-12T07:25:32Z","annotations":{"kubectl.kubernetes.io/last-applied-configuration":"{\"apiVersion\":\"v1\",\"kind\":\"Namespace\",\"metadata\":{\"annotations\":{},\"name\":\"kube-system\"}}\n"},"managedFields":[{"manager":"kube-apiserver","operation":"Update","apiVersion":"v1","time":"2020-11-12T07:25:32Z","fieldsType":"FieldsV1","fieldsV1":{"f:status":{"f:phase":{}}}},{"manager":"kubectl-client-side-apply","operation":"Update","apiVersion":"v1","time":"2020-11-12T07:29:44Z","fieldsType":"FieldsV1","fieldsV1":{"f:metadata":{"f:annotations":{".":{},"f:kubectl.kubernetes.io/last-applied-configuration":{}}}}}]},"spec":{"finalizers":["kubernetes"]},"status":{"phase":"Active"}},{"metadata":{"name":"kubeflow-operators","selfLink":"/api/v1/namespaces/kubeflow-operators","uid":"7a506123-310a-48b7-8c4c-ea95238ed559","resourceVersion":"31999589","creationTimestamp":"2021-01-28T09:08:10Z","managedFields":[{"manager":"kubectl-create","operation":"Update","apiVersion":"v1","time":"2021-01-28T09:08:10Z","fieldsType":"FieldsV1","fieldsV1":{"f:status":{"f:phase":{}}}}]},"spec":{"finalizers":["kubernetes"]},"status":{"phase":"Active"}},{"metadata":{"name":"monitoring","selfLink":"/api/v1/namespaces/monitoring","uid":"28f94d9b-781a-4503-8704-05be7fc0b03f","resourceVersion":"1932","creationTimestamp":"2020-11-12T07:34:49Z","annotations":{"kubectl.kubernetes.io/last-applied-configuration":"{\"apiVersion\":\"v1\",\"kind\":\"Namespace\",\"metadata\":{\"annotations\":{},\"name\":\"monitoring\"}}\n"},"managedFields":[{"manager":"kubectl-client-side-apply","operation":"Update","apiVersion":"v1","time":"2020-11-12T07:34:49Z","fieldsType":"FieldsV1","fieldsV1":{"f:metadata":{"f:annotations":{".":{},"f:kubectl.kubernetes.io/last-applied-configuration":{}}},"f:status":{"f:phase":{}}}}]},"spec":{"finalizers":["kubernetes"]},"status":{"phase":"Active"}},{"metadata":{"name":"portainer","selfLink":"/api/v1/namespaces/portainer","uid":"65ce6ed6-be89-4da5-86da-8a5decf8b190","resourceVersion":"45415995","creationTimestamp":"2021-02-25T08:26:29Z","annotations":{"kubectl.kubernetes.io/last-applied-configuration":"{\"apiVersion\":\"v1\",\"kind\":\"Namespace\",\"metadata\":{\"annotations\":{},\"name\":\"portainer\"}}\n"},"managedFields":[{"manager":"kubectl-client-side-apply","operation":"Update","apiVersion":"v1","time":"2021-02-25T08:26:29Z","fieldsType":"FieldsV1","fieldsV1":{"f:metadata":{"f:annotations":{".":{},"f:kubectl.kubernetes.io/last-applied-configuration":{}}},"f:status":{"f:phase":{}}}}]},"spec":{"finalizers":["kubernetes"]},"status":{"phase":"Active"}},{"metadata":{"name":"rook-ceph","selfLink":"/api/v1/namespaces/rook-ceph","uid":"e4756739-9b75-43ac-8870-60191e336917","resourceVersion":"1716232","creationTimestamp":"2020-11-16T07:37:55Z","managedFields":[{"manager":"kubectl-create","operation":"Update","apiVersion":"v1","time":"2020-11-16T07:37:55Z","fieldsType":"FieldsV1","fieldsV1":{"f:status":{"f:phase":{}}}}]},"spec":{"finalizers":["kubernetes"]},"status":{"phase":"Active"}},{"metadata":{"name":"traefik-system","selfLink":"/api/v1/namespaces/traefik-system","uid":"ed85f7ef-2805-4ba7-84d1-5ae430471202","resourceVersion":"1381","creationTimestamp":"2020-11-12T07:31:22Z","managedFields":[{"manager":"kubectl-create","operation":"Update","apiVersion":"v1","time":"2020-11-12T07:31:22Z","fieldsType":"FieldsV1","fieldsV1":{"f:status":{"f:phase":{}}}}]},"spec":{"finalizers":["kubernetes"]},"status":{"phase":"Active"}}]}

    +
  • +
  • 通过启动 proxy 获取集群配置信息

    +
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    $ kubectl proxy --port=8081 & curl http://localhost:8081/api/
    {
    "kind": "APIVersions",
    "versions": [
    "v1"
    ],
    "serverAddressByClientCIDRs": [
    {
    "clientCIDR": "0.0.0.0/0",
    "serverAddress": "10.114.1.100:6443"
    }
    ]
    }
    +
  • +
  • 查看集群各组件信息

    +
    1
    2
    3
    4
    5
    6
    $ kubectl cluster-info
    Kubernetes master is running at https://10.114.1.100:6443
    CoreDNS is running at https://10.114.1.100:6443/api/v1/namespaces/kube-system/services/kube-dns:dns/proxy
    kubernetes-dashboard is running at https://10.114.1.100:6443/api/v1/namespaces/kube-system/services/https:kubernetes-dashboard:/proxy
    Metrics-server is running at https://10.114.1.100:6443/api/v1/namespaces/kube-system/services/https:metrics-server:/proxy

    + +
  • +
+

curl 访问

    +
  • 在 pod 里面访问

    +
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    $ TOKEN=$(cat /run/secrets/kubernetes.io/serviceaccount/token)
    $ CACERT=/run/secrets/kubernetes.io/serviceaccount/ca.crt
    $ curl --cacert $CACERT --header "Authorization: Bearer $TOKEN" https://$KUBERNETES_SERVICE_HOST:$KUBERNETES_SERVICE_PORT/api
    {
    "kind": "APIVersions",
    "versions": [
    "v1"
    ],
    "serverAddressByClientCIDRs": [
    {
    "clientCIDR": "0.0.0.0/0",
    "serverAddress": "10.114.1.110:6443"(另外一个master节点ip)
    }
    ]
    }
    +
  • +
  • 在 master 节点上访问

    +
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    $ APISERVER=$(kubectl config view | grep server | cut -f 2- -d ":" | tr -d " ")
    $ TOKEN=$(kubectl describe secret $(kubectl get secrets | grep default | cut -f1 -d ' ') | grep -E '^token'| cut -f2 -d':'| tr -d '\t')
    $ curl $APISERVER/api --header "Authorization: Bearer $TOKEN" --insecure
    {
    "kind": "Status",
    "apiVersion": "v1",
    "metadata": {

    },
    "status": "Failure",
    "message": "Unauthorized",
    "reason": "Unauthorized",
    "code": 401
    }
    +

    参考

  • +
  • kube-apiserver

    +
  • +
  • kubernetes 组件

    +
  • +
+ + +
+ +
+
+ + + + + + +
+
+
[Kubernetes] Kubernetes 核心组件之 kube-apiserver
+
https://crisescode.github.io/blog/2021/11/15/Kubernetes-Kubernetes-核心组件之-kube-apiserver/
+
+
+ +
+
作者
+
Crise
+
+ + +
+
发布于
+
2021年11月15日
+
+ + + +
+
许可协议
+
+ + + + + + + + + + +
+
+ +
+
+
+ + + + +
+ + +
+ +
+ + +
+ +
+
+ + + + +
+ + +
+ + +
+
+
+
+ +
+ + + + +
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git "a/2023/04/13/GO-golang\344\270\255\344\274\230\351\233\205\350\256\276\347\275\256\345\217\202\346\225\260\351\273\230\350\256\244\345\200\274/index.html" "b/2023/04/13/GO-golang\344\270\255\344\274\230\351\233\205\350\256\276\347\275\256\345\217\202\346\225\260\351\273\230\350\256\244\345\200\274/index.html" new file mode 100644 index 0000000..835204b --- /dev/null +++ "b/2023/04/13/GO-golang\344\270\255\344\274\230\351\233\205\350\256\276\347\275\256\345\217\202\346\225\260\351\273\230\350\256\244\345\200\274/index.html" @@ -0,0 +1,775 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + [GO] golang中优雅设置参数默认值 - LuckyCrise + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ + + + + + +
+ +
+ +
+ + + +
+
+
+ + +
+ +
+
+
+
+ +

[GO] golang中优雅设置参数默认值

+ + +
+ +

前言

今天在使用 golang 重构 python 站点时,遇到了一个有趣的事情。就是在 python 函数中参数是可以设置默认值的,这样在函数调用时,就不需要每个参数都传一个值,其实这也是变相的实现重载功能。但是我发现在 golang 中参数是不能设置默认值的,但是基于程序员的直觉,相信此事没那么简单,于是抱着打破沙锅问到底的态度,就有了这篇文章。

+

不设置默认值带来的不便

首先,通过一个例子,说明我在编码过程中遇到的问题。对于平台后端开发工程师来说,会经常遇到以下场景:
通过

+
    +
  • 通过多种条件查询数据库记录,比如:select * from user where user_name in (xxx, xxx, xx) and user_region = “shanghai” order by id desc;
  • +
  • 需要在不同功能模块做以上方式查询。
  • +
+

基于此,我将这些查询方式抽象成一个方法,之后所有的功能模块,都可以使用该方法进行多条件联合查询数据记录,具体抽象如下:

+
1
2
3
func DBQueryAllWithConditions(ctx context.Context, orderBy map[string]string, eqFilters map[string]interface{}, inFilters map[string]interface{}, likeFilters map[string]string) {

}
+ +

研读开源代码的优雅实现

改进自己的代码

总结

+ +
+ +
+
+ + + + + + +
+
+
[GO] golang中优雅设置参数默认值
+
https://crisescode.github.io/blog/2023/04/13/GO-golang中优雅设置参数默认值/
+
+
+ +
+
作者
+
Crise
+
+ + +
+
发布于
+
2023年4月13日
+
+ + + +
+
许可协议
+
+ + + + + + + + + + +
+
+ +
+
+
+ + + + +
+ + +
+ +
+ + +
+ +
+
+ + + + +
+ + +
+ + +
+
+
+
+ +
+ + + + +
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/2024/09/04/hello-world/index.html b/2024/09/04/hello-world/index.html new file mode 100644 index 0000000..e829131 --- /dev/null +++ b/2024/09/04/hello-world/index.html @@ -0,0 +1,743 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 如何使用 hexo 新建文章 - LuckyCrise + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ + + + + + +
+ +
+ +
+ + + +
+
+
+ + +
+ +
+
+
+
+ +

如何使用 hexo 新建文章

+ + +
+ +

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.

+

Quick Start

Create a new post

1
$ hexo new "My New Post"
+ +

More info: Writing

+

Run server

1
$ hexo server
+ +

More info: Server

+

Generate static files

1
$ hexo generate
+ +

More info: Generating

+

Deploy to remote sites

1
$ hexo deploy
+ +

More info: Deployment

+ + +
+ +
+
+ + + + + + +
+
+
如何使用 hexo 新建文章
+
https://crisescode.github.io/blog/2024/09/04/hello-world/
+
+
+ +
+
作者
+
Crise
+
+ + +
+
发布于
+
2024年9月4日
+
+ + + +
+
许可协议
+
+ + + + + + + + + + +
+
+ +
+
+
+ + + + +
+
+ + +
+ +
+ +
+ + +
+ +
+
+ + + + +
+ + +
+ + +
+
+
+
+ +
+ + + + +
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/404.html b/404.html new file mode 100644 index 0000000..4ee8d6b --- /dev/null +++ b/404.html @@ -0,0 +1,416 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 页面不存在 - LuckyCrise + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ + + + + + +
+ +
+ +
+ + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/about/index.html b/about/index.html new file mode 100644 index 0000000..ebe6773 --- /dev/null +++ b/about/index.html @@ -0,0 +1,430 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 关于Crise - LuckyCrise + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ + + + + + +
+ +
+ +
+ +
+
+ +
+
+
+ + +
+

关于我

95年后端程序员,先后在联想,信也科技(至今)搬砖,主要从事容器云机器学习平台系统开发相关工作。
对LLM,MLSys,MLOps,容器云,Kubernetes,Golang 等技术感兴趣。

+

找到我

+ + + +
+ + + +
+
+
+
+
+ + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/archives/2020/06/index.html b/archives/2020/06/index.html new file mode 100644 index 0000000..4a2b6b1 --- /dev/null +++ b/archives/2020/06/index.html @@ -0,0 +1,456 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 归档 - LuckyCrise + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ + + + + + +
+ +
+ +
+ + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/archives/2020/07/index.html b/archives/2020/07/index.html new file mode 100644 index 0000000..a805cb3 --- /dev/null +++ b/archives/2020/07/index.html @@ -0,0 +1,498 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 归档 - LuckyCrise + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ + + + + + +
+ +
+ +
+ + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/archives/2020/07/page/2/index.html b/archives/2020/07/page/2/index.html new file mode 100644 index 0000000..1383ecb --- /dev/null +++ b/archives/2020/07/page/2/index.html @@ -0,0 +1,450 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 归档 - LuckyCrise + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ + + + + + +
+ +
+ +
+ +
+
+ +
+
+
+ + +
+

共计 29 篇文章

+
+ + + + +

2020

+ + + +
剑指offer 第二天
+
+ + + + +
剑指offer 第一天
+
+ +
+ + + + + + + +
+
+
+
+
+ + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/archives/2020/08/index.html b/archives/2020/08/index.html new file mode 100644 index 0000000..bfdfd15 --- /dev/null +++ b/archives/2020/08/index.html @@ -0,0 +1,444 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 归档 - LuckyCrise + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ + + + + + +
+ +
+ +
+ +
+
+ + +
+
+ + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/archives/2020/09/index.html b/archives/2020/09/index.html new file mode 100644 index 0000000..92bd6ab --- /dev/null +++ b/archives/2020/09/index.html @@ -0,0 +1,444 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 归档 - LuckyCrise + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ + + + + + +
+ +
+ +
+ + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/archives/2020/10/index.html b/archives/2020/10/index.html new file mode 100644 index 0000000..c45980d --- /dev/null +++ b/archives/2020/10/index.html @@ -0,0 +1,444 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 归档 - LuckyCrise + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ + + + + + +
+ +
+ +
+ +
+
+ +
+
+
+ + + + + + + + +
+
+
+
+
+ + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/archives/2020/12/index.html b/archives/2020/12/index.html new file mode 100644 index 0000000..f21ddc8 --- /dev/null +++ b/archives/2020/12/index.html @@ -0,0 +1,444 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 归档 - LuckyCrise + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ + + + + + +
+ +
+ +
+ +
+ +
+ + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/archives/2020/index.html b/archives/2020/index.html new file mode 100644 index 0000000..e3ef655 --- /dev/null +++ b/archives/2020/index.html @@ -0,0 +1,498 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 归档 - LuckyCrise + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ + + + + + +
+ +
+ +
+ + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/archives/2020/page/2/index.html b/archives/2020/page/2/index.html new file mode 100644 index 0000000..d8c5b7e --- /dev/null +++ b/archives/2020/page/2/index.html @@ -0,0 +1,498 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 归档 - LuckyCrise + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ + + + + + +
+ +
+ +
+ + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/archives/2020/page/3/index.html b/archives/2020/page/3/index.html new file mode 100644 index 0000000..9181356 --- /dev/null +++ b/archives/2020/page/3/index.html @@ -0,0 +1,462 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 归档 - LuckyCrise + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ + + + + + +
+ +
+ +
+ + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/archives/2021/01/index.html b/archives/2021/01/index.html new file mode 100644 index 0000000..209f319 --- /dev/null +++ b/archives/2021/01/index.html @@ -0,0 +1,444 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 归档 - LuckyCrise + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ + + + + + +
+ +
+ +
+ +
+
+ +
+
+
+ + + + + + + + +
+
+
+
+
+ + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/archives/2021/11/index.html b/archives/2021/11/index.html new file mode 100644 index 0000000..30a48a1 --- /dev/null +++ b/archives/2021/11/index.html @@ -0,0 +1,438 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 归档 - LuckyCrise + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ + + + + + +
+ +
+ +
+ +
+
+ +
+
+
+ + +
+

共计 29 篇文章

+
+ + + + +

2021

+ + + +
[Kubernetes] Kubernetes 核心组件之 kube-apiserver
+
+ +
+ + + + + +
+
+
+
+
+ + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/archives/2021/index.html b/archives/2021/index.html new file mode 100644 index 0000000..c336b09 --- /dev/null +++ b/archives/2021/index.html @@ -0,0 +1,450 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 归档 - LuckyCrise + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ + + + + + +
+ +
+ +
+ + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/archives/2023/04/index.html b/archives/2023/04/index.html new file mode 100644 index 0000000..ba12fa1 --- /dev/null +++ b/archives/2023/04/index.html @@ -0,0 +1,438 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 归档 - LuckyCrise + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ + + + + + +
+ +
+ +
+ +
+
+ +
+
+
+ + +
+

共计 29 篇文章

+
+ + + + +

2023

+ + + +
[GO] golang中优雅设置参数默认值
+
+ +
+ + + + + +
+
+
+
+
+ + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/archives/2023/index.html b/archives/2023/index.html new file mode 100644 index 0000000..b3f7256 --- /dev/null +++ b/archives/2023/index.html @@ -0,0 +1,438 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 归档 - LuckyCrise + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ + + + + + +
+ +
+ +
+ +
+
+ +
+
+
+ + +
+

共计 29 篇文章

+
+ + + + +

2023

+ + + +
[GO] golang中优雅设置参数默认值
+
+ +
+ + + + + +
+
+
+
+
+ + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/archives/2024/09/index.html b/archives/2024/09/index.html new file mode 100644 index 0000000..9c85349 --- /dev/null +++ b/archives/2024/09/index.html @@ -0,0 +1,438 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 归档 - LuckyCrise + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ + + + + + +
+ +
+ +
+ +
+
+ +
+
+
+ + +
+

共计 29 篇文章

+
+ + + + +

2024

+ + + +
如何使用 hexo 新建文章
+
+ +
+ + + + + +
+
+
+
+
+ + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/archives/2024/index.html b/archives/2024/index.html new file mode 100644 index 0000000..824c885 --- /dev/null +++ b/archives/2024/index.html @@ -0,0 +1,438 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 归档 - LuckyCrise + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ + + + + + +
+ +
+ +
+ +
+
+ +
+
+
+ + +
+

共计 29 篇文章

+
+ + + + +

2024

+ + + +
如何使用 hexo 新建文章
+
+ +
+ + + + + +
+
+
+
+
+ + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/archives/index.html b/archives/index.html new file mode 100644 index 0000000..423f579 --- /dev/null +++ b/archives/index.html @@ -0,0 +1,507 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 归档 - LuckyCrise + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ + + + + + +
+ +
+ +
+ + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/archives/page/2/index.html b/archives/page/2/index.html new file mode 100644 index 0000000..57a73da --- /dev/null +++ b/archives/page/2/index.html @@ -0,0 +1,498 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 归档 - LuckyCrise + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ + + + + + +
+ +
+ +
+ + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/archives/page/3/index.html b/archives/page/3/index.html new file mode 100644 index 0000000..c30d227 --- /dev/null +++ b/archives/page/3/index.html @@ -0,0 +1,492 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 归档 - LuckyCrise + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ + + + + + +
+ +
+ +
+ + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/atom.xml b/atom.xml new file mode 100644 index 0000000..a8df1f6 --- /dev/null +++ b/atom.xml @@ -0,0 +1,521 @@ + + + LuckyCrise + + + + + + 2024-09-04T15:19:27.781Z + https://crisescode.github.io/blog/ + + + Crise + + + + Hexo + + + 如何使用 hexo 新建文章 + + https://crisescode.github.io/blog/2024/09/04/hello-world/ + 2024-09-04T15:18:54.000Z + 2024-09-04T15:19:27.781Z + + 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.

Quick Start

Create a new post

1
$ hexo new "My New Post"

More info: Writing

Run server

1
$ hexo server

More info: Server

Generate static files

1
$ hexo generate

More info: Generating

Deploy to remote sites

1
$ hexo deploy

More info: Deployment

]]>
+ + + + + + <p>Welcome to <a href="https://hexo.io/">Hexo</a>! This is your very first post. Check <a href="https://hexo.io/docs/">documentation</a> for + + + + + + +
+ + + [GO] golang中优雅设置参数默认值 + + https://crisescode.github.io/blog/2023/04/13/GO-golang%E4%B8%AD%E4%BC%98%E9%9B%85%E8%AE%BE%E7%BD%AE%E5%8F%82%E6%95%B0%E9%BB%98%E8%AE%A4%E5%80%BC/ + 2023-04-13T15:55:33.000Z + 2024-09-04T14:46:05.630Z + + 前言

今天在使用 golang 重构 python 站点时,遇到了一个有趣的事情。就是在 python 函数中参数是可以设置默认值的,这样在函数调用时,就不需要每个参数都传一个值,其实这也是变相的实现重载功能。但是我发现在 golang 中参数是不能设置默认值的,但是基于程序员的直觉,相信此事没那么简单,于是抱着打破沙锅问到底的态度,就有了这篇文章。

不设置默认值带来的不便

首先,通过一个例子,说明我在编码过程中遇到的问题。对于平台后端开发工程师来说,会经常遇到以下场景:
通过

  • 通过多种条件查询数据库记录,比如:select * from user where user_name in (xxx, xxx, xx) and user_region = “shanghai” order by id desc;
  • 需要在不同功能模块做以上方式查询。

基于此,我将这些查询方式抽象成一个方法,之后所有的功能模块,都可以使用该方法进行多条件联合查询数据记录,具体抽象如下:

1
2
3
func DBQueryAllWithConditions(ctx context.Context, orderBy map[string]string, eqFilters map[string]interface{}, inFilters map[string]interface{}, likeFilters map[string]string) {

}

研读开源代码的优雅实现

改进自己的代码

总结

]]>
+ + + + + + <h2 id="前言"><a href="#前言" class="headerlink" title="前言"></a>前言</h2><p>今天在使用 golang 重构 python 站点时,遇到了一个有趣的事情。就是在 python 函数中参数是可以设置默认值的,这样在函数调 + + + + + + + + + + +
+ + + [Kubernetes] Kubernetes 核心组件之 kube-apiserver + + https://crisescode.github.io/blog/2021/11/15/Kubernetes-Kubernetes-%E6%A0%B8%E5%BF%83%E7%BB%84%E4%BB%B6%E4%B9%8B-kube-apiserver/ + 2021-11-15T14:36:19.000Z + 2024-09-04T14:46:05.630Z + + kube-apiserverKubernetes 最重要的核心组件之一,主要能提供的功能如下:

  • 给集群其他组件提供数据交互以及通信枢纽功能,以RESTful API 的形式提供其他组件查询,修改集群状态的 CURD(Create,Read,Update,Detele)接口,然后将状态储存到 etcd 中;
  • 为用户请求接入认证,授权以及准入控制等功能;
  • 并且可以用来处理乐观锁, 当有并发更新的情况, 对对象做更改就不会被其他客户端覆盖。

如何部署

工作原理

kube-apiserver 提供了 KubernetesREST API,实现了认证、授权、准入控制等安全校验功能,同时也负责集群状态的存储操作(通过 etcd)。

认证

授权

准入控制

API 访问示例

kube-apiserver 提供了为每种语言提供了 SDK,方便用户访问集群其他组件,以及将数据存储或更新到etcd中,如下:

kubectl 访问

  • 查询 kube-apiserver 支持API的版本

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    $ kubectl api-versions
    admissionregistration.k8s.io/v1
    admissionregistration.k8s.io/v1beta1
    apiextensions.k8s.io/v1
    apiextensions.k8s.io/v1beta1
    apps/v1

    ...

    scheduling.k8s.io/v1
    scheduling.k8s.io/v1beta1
    storage.k8s.io/v1
    storage.k8s.io/v1beta1
    traefik.containo.us/v1alpha1
    v1
    xgboostjob.kubeflow.org/v1

  • 查询 kube-apiserver 支持API的资源对象

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    $ kubectl api-resources
    NAME SHORTNAMES APIGROUP NAMESPACED KIND
    bindings true Binding
    componentstatuses cs false ComponentStatus
    configmaps cm true ConfigMap

    ...

    tlsoptions traefik.containo.us true TLSOption
    tlsstores traefik.containo.us true TLSStore
    traefikservices traefik.containo.us true TraefikService
    xgboostjobs xgboostjob.kubeflow.org true XGBoostJob

  • 查看 kube-apiserverv1/namepsace 信息

    1
    2
    3
    $ kubectl get --raw /api/v1/namespaces
    {"kind":"NamespaceList","apiVersion":"v1","metadata":{"selfLink":"/api/v1/namespaces","resourceVersion":"190115288"},"items":[{"metadata":{"name":"airflow","selfLink":"/api/v1/namespaces/airflow","uid":"f4756c7a-8bd7-4988-a69c-c849a3c035be","resourceVersion":"79499605","creationTimestamp":"2021-05-06T07:39:19Z","managedFields":[{"manager":"kubectl-create","operation":"Update","apiVersion":"v1","time":"2021-05-06T07:39:19Z","fieldsType":"FieldsV1","fieldsV1":{"f:status":{"f:phase":{}}}}]},"spec":{"finalizers":["kubernetes"]},"status":{"phase":"Active"}},{"metadata":{"name":"crise","selfLink":"/api/v1/namespaces/crise","uid":"6f943c7a-8419-4c95-bf5a-2972f3631aab","resourceVersion":"155793497","creationTimestamp":"2021-09-26T05:09:22Z","managedFields":[{"manager":"kubectl-create","operation":"Update","apiVersion":"v1","time":"2021-09-26T05:09:22Z","fieldsType":"FieldsV1","fieldsV1":{"f:status":{"f:phase":{}}}}]},"spec":{"finalizers":["kubernetes"]},"status":{"phase":"Active"}},{"metadata":{"name":"default","selfLink":"/api/v1/namespaces/default","uid":"545db544-c735-4d06-a600-981144f245a8","resourceVersion":"157","creationTimestamp":"2020-11-12T07:25:33Z","managedFields":[{"manager":"kube-apiserver","operation":"Update","apiVersion":"v1","time":"2020-11-12T07:25:33Z","fieldsType":"FieldsV1","fieldsV1":{"f:status":{"f:phase":{}}}}]},"spec":{"finalizers":["kubernetes"]},"status":{"phase":"Active"}},{"metadata":{"name":"elastic","selfLink":"/api/v1/namespaces/elastic","uid":"adcddefd-2a71-4b65-af74-ec4d5ac854b4","resourceVersion":"132059434","creationTimestamp":"2021-08-10T08:36:48Z","labels":{"name":"elastic"},"managedFields":[{"manager":"Go-http-client","operation":"Update","apiVersion":"v1","time":"2021-08-10T08:36:48Z","fieldsType":"FieldsV1","fieldsV1":{"f:metadata":{"f:labels":{".":{},"f:name":{}}},"f:status":{"f:phase":{}}}}]},"spec":{"finalizers":["kubernetes"]},"status":{"phase":"Active"}},{"metadata":{"name":"kafka","selfLink":"/api/v1/namespaces/kafka","uid":"82f78a4a-b135-49af-a6d2-34b162deff34","resourceVersion":"126083706","creationTimestamp":"2021-07-30T06:28:47Z","labels":{"name":"kafka"},"managedFields":[{"manager":"Go-http-client","operation":"Update","apiVersion":"v1","time":"2021-07-30T06:28:47Z","fieldsType":"FieldsV1","fieldsV1":{"f:metadata":{"f:labels":{".":{},"f:name":{}}},"f:status":{"f:phase":{}}}}]},"spec":{"finalizers":["kubernetes"]},"status":{"phase":"Active"}},{"metadata":{"name":"kube-node-lease","selfLink":"/api/v1/namespaces/kube-node-lease","uid":"16073100-6a4c-4275-9cb4-914d16e92dd9","resourceVersion":"43","creationTimestamp":"2020-11-12T07:25:32Z","managedFields":[{"manager":"kube-apiserver","operation":"Update","apiVersion":"v1","time":"2020-11-12T07:25:32Z","fieldsType":"FieldsV1","fieldsV1":{"f:status":{"f:phase":{}}}}]},"spec":{"finalizers":["kubernetes"]},"status":{"phase":"Active"}},{"metadata":{"name":"kube-public","selfLink":"/api/v1/namespaces/kube-public","uid":"f6077460-b5ab-4250-ad00-bd7a32745873","resourceVersion":"41","creationTimestamp":"2020-11-12T07:25:32Z","managedFields":[{"manager":"kube-apiserver","operation":"Update","apiVersion":"v1","time":"2020-11-12T07:25:32Z","fieldsType":"FieldsV1","fieldsV1":{"f:status":{"f:phase":{}}}}]},"spec":{"finalizers":["kubernetes"]},"status":{"phase":"Active"}},{"metadata":{"name":"kube-system","selfLink":"/api/v1/namespaces/kube-system","uid":"4671dc1b-9f93-4c23-be43-65579ff03293","resourceVersion":"1051","creationTimestamp":"2020-11-12T07:25:32Z","annotations":{"kubectl.kubernetes.io/last-applied-configuration":"{\"apiVersion\":\"v1\",\"kind\":\"Namespace\",\"metadata\":{\"annotations\":{},\"name\":\"kube-system\"}}\n"},"managedFields":[{"manager":"kube-apiserver","operation":"Update","apiVersion":"v1","time":"2020-11-12T07:25:32Z","fieldsType":"FieldsV1","fieldsV1":{"f:status":{"f:phase":{}}}},{"manager":"kubectl-client-side-apply","operation":"Update","apiVersion":"v1","time":"2020-11-12T07:29:44Z","fieldsType":"FieldsV1","fieldsV1":{"f:metadata":{"f:annotations":{".":{},"f:kubectl.kubernetes.io/last-applied-configuration":{}}}}}]},"spec":{"finalizers":["kubernetes"]},"status":{"phase":"Active"}},{"metadata":{"name":"kubeflow-operators","selfLink":"/api/v1/namespaces/kubeflow-operators","uid":"7a506123-310a-48b7-8c4c-ea95238ed559","resourceVersion":"31999589","creationTimestamp":"2021-01-28T09:08:10Z","managedFields":[{"manager":"kubectl-create","operation":"Update","apiVersion":"v1","time":"2021-01-28T09:08:10Z","fieldsType":"FieldsV1","fieldsV1":{"f:status":{"f:phase":{}}}}]},"spec":{"finalizers":["kubernetes"]},"status":{"phase":"Active"}},{"metadata":{"name":"monitoring","selfLink":"/api/v1/namespaces/monitoring","uid":"28f94d9b-781a-4503-8704-05be7fc0b03f","resourceVersion":"1932","creationTimestamp":"2020-11-12T07:34:49Z","annotations":{"kubectl.kubernetes.io/last-applied-configuration":"{\"apiVersion\":\"v1\",\"kind\":\"Namespace\",\"metadata\":{\"annotations\":{},\"name\":\"monitoring\"}}\n"},"managedFields":[{"manager":"kubectl-client-side-apply","operation":"Update","apiVersion":"v1","time":"2020-11-12T07:34:49Z","fieldsType":"FieldsV1","fieldsV1":{"f:metadata":{"f:annotations":{".":{},"f:kubectl.kubernetes.io/last-applied-configuration":{}}},"f:status":{"f:phase":{}}}}]},"spec":{"finalizers":["kubernetes"]},"status":{"phase":"Active"}},{"metadata":{"name":"portainer","selfLink":"/api/v1/namespaces/portainer","uid":"65ce6ed6-be89-4da5-86da-8a5decf8b190","resourceVersion":"45415995","creationTimestamp":"2021-02-25T08:26:29Z","annotations":{"kubectl.kubernetes.io/last-applied-configuration":"{\"apiVersion\":\"v1\",\"kind\":\"Namespace\",\"metadata\":{\"annotations\":{},\"name\":\"portainer\"}}\n"},"managedFields":[{"manager":"kubectl-client-side-apply","operation":"Update","apiVersion":"v1","time":"2021-02-25T08:26:29Z","fieldsType":"FieldsV1","fieldsV1":{"f:metadata":{"f:annotations":{".":{},"f:kubectl.kubernetes.io/last-applied-configuration":{}}},"f:status":{"f:phase":{}}}}]},"spec":{"finalizers":["kubernetes"]},"status":{"phase":"Active"}},{"metadata":{"name":"rook-ceph","selfLink":"/api/v1/namespaces/rook-ceph","uid":"e4756739-9b75-43ac-8870-60191e336917","resourceVersion":"1716232","creationTimestamp":"2020-11-16T07:37:55Z","managedFields":[{"manager":"kubectl-create","operation":"Update","apiVersion":"v1","time":"2020-11-16T07:37:55Z","fieldsType":"FieldsV1","fieldsV1":{"f:status":{"f:phase":{}}}}]},"spec":{"finalizers":["kubernetes"]},"status":{"phase":"Active"}},{"metadata":{"name":"traefik-system","selfLink":"/api/v1/namespaces/traefik-system","uid":"ed85f7ef-2805-4ba7-84d1-5ae430471202","resourceVersion":"1381","creationTimestamp":"2020-11-12T07:31:22Z","managedFields":[{"manager":"kubectl-create","operation":"Update","apiVersion":"v1","time":"2020-11-12T07:31:22Z","fieldsType":"FieldsV1","fieldsV1":{"f:status":{"f:phase":{}}}}]},"spec":{"finalizers":["kubernetes"]},"status":{"phase":"Active"}}]}

  • 通过启动 proxy 获取集群配置信息

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    $ kubectl proxy --port=8081 & curl http://localhost:8081/api/
    {
    "kind": "APIVersions",
    "versions": [
    "v1"
    ],
    "serverAddressByClientCIDRs": [
    {
    "clientCIDR": "0.0.0.0/0",
    "serverAddress": "10.114.1.100:6443"
    }
    ]
    }
  • 查看集群各组件信息

    1
    2
    3
    4
    5
    6
    $ kubectl cluster-info
    Kubernetes master is running at https://10.114.1.100:6443
    CoreDNS is running at https://10.114.1.100:6443/api/v1/namespaces/kube-system/services/kube-dns:dns/proxy
    kubernetes-dashboard is running at https://10.114.1.100:6443/api/v1/namespaces/kube-system/services/https:kubernetes-dashboard:/proxy
    Metrics-server is running at https://10.114.1.100:6443/api/v1/namespaces/kube-system/services/https:metrics-server:/proxy

curl 访问

  • 在 pod 里面访问

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    $ TOKEN=$(cat /run/secrets/kubernetes.io/serviceaccount/token)
    $ CACERT=/run/secrets/kubernetes.io/serviceaccount/ca.crt
    $ curl --cacert $CACERT --header "Authorization: Bearer $TOKEN" https://$KUBERNETES_SERVICE_HOST:$KUBERNETES_SERVICE_PORT/api
    {
    "kind": "APIVersions",
    "versions": [
    "v1"
    ],
    "serverAddressByClientCIDRs": [
    {
    "clientCIDR": "0.0.0.0/0",
    "serverAddress": "10.114.1.110:6443"(另外一个master节点ip)
    }
    ]
    }
  • 在 master 节点上访问

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    $ APISERVER=$(kubectl config view | grep server | cut -f 2- -d ":" | tr -d " ")
    $ TOKEN=$(kubectl describe secret $(kubectl get secrets | grep default | cut -f1 -d ' ') | grep -E '^token'| cut -f2 -d':'| tr -d '\t')
    $ curl $APISERVER/api --header "Authorization: Bearer $TOKEN" --insecure
    {
    "kind": "Status",
    "apiVersion": "v1",
    "metadata": {

    },
    "status": "Failure",
    "message": "Unauthorized",
    "reason": "Unauthorized",
    "code": 401
    }

    参考

  • kube-apiserver

  • kubernetes 组件

]]>
+ + + + <p><code>kube-apiserver</code> 是 <code>Kubernetes</code> 最重要的核心组件之一,主要能提供的功能如下:</p> +<ul> +<li>给集群其他组件提供数据交互以及通信枢纽功能,以<code>RESTful API</code> 的形式提供其他组件查询,修改集群状态的 <code>CURD(Create,Read,Update,Detele)</code>接口,然后将状态储存到 <code>etcd</code> 中;</li> +<li>为用户请求接入认证,授权以及准入控制等功能;</li> +<li>并且可以用来处理乐观锁, 当有并发更新的情况, 对对象做更改就不会被其他客户端覆盖。 + + + + + + + + + + + +
+ + + [Kubernetes] Kubernetes 中的弹性伸缩以及自动扩容 + + https://crisescode.github.io/blog/2021/01/24/Kubernetes-Kubernetes-%E4%B8%AD%E7%9A%84%E5%BC%B9%E6%80%A7%E4%BC%B8%E7%BC%A9%E4%BB%A5%E5%8F%8A%E8%87%AA%E5%8A%A8%E6%89%A9%E5%AE%B9/ + 2021-01-24T14:44:58.000Z + 2024-09-04T14:46:05.630Z + + + + + + + + + + + + + + + + + + + 2020 年终总结 + + https://crisescode.github.io/blog/2021/01/12/2020-%E5%B9%B4%E7%BB%88%E6%80%BB%E7%BB%93/ + 2021-01-12T15:09:00.000Z + 2024-09-04T14:46:05.630Z + + 一直以来自己是不喜欢将一些总结放到博客里来的,感觉这个还是挺私密的,是自己一年的发展回顾。但是看了很多大佬的博客,他们都很擅于总结自己的一年,并且也会将之发到自己的博客上,我感觉这样也挺好的。自己之前都是将这些总结放到本地存储,但这样有时写了一会就不想去写了,很容易虎头蛇尾。因此我决定以后可以将一些总结,感触什么的放到博客里,以此来监督自己一直坚持下去~

2020,一个不平凡的一年,这整年人人都基本是带着口罩过来的,直到现在还是无法摆脱带口罩,每天出行仍需带着上地铁,进公司。在年初,因为疫情影响,相信很多人都是被困在家远程办公。刚开始在家办公,自己还是不适应的,没有公司的那种开发氛围,很多需求也不能面对面及时的沟通得以解决,这样还是挺不方便的。但是后来,随着在家办公的时间长了,感觉在家办公也不错,至少节省了上下班通勤路上的时间,每天从床上爬起来就可以投入工作,这种感觉还是挺好的。当然这样对于大多数人工作效率肯定是很低的,所以公司还是会尽量要求员工在家隔离完就需要回公司办公了,因此自己大概在今年3月份回到联想大厦办公了。

其实自己在年初的时候给自己的2020定了一些计划的,但是关于实现与否,还真是偏差甚远。首先是打算这一年换一份工作的,最好是NLP算法工程师相关的工作。在今年的前三个月里,自己还是很认真的在学习NLP相关的知识,但是后面发现自己还是很难去找这相关的工作,加上后面在联想又大部分时间在做开发相关的工作,所以后面也就没再学习了。关于跳槽,从今年8月份开始更新几个网站的简历,然后也是8月份开始陆续接到了很多猎头的电话,也面试了很多了公司,最终拿了几个offer,待遇什么的较联想这边也有一定的涨幅。最后选择了一家互联网+金融的公司,信也科技,但不是算法相关的岗位,不过也挺符合自己的发展方向的,目前主要是机器学习容器云平台开发,主要是
Python / Go 作为技术栈, 基于 Kubernetes / Docker 打造基于云原生上传数据集,标注,特征提取,训练以及模型部署一体化的机器学习平台。

]]>
+ + + + <p>一直以来自己是不喜欢将一些总结放到博客里来的,感觉这个还是挺私密的,是自己一年的发展回顾。但是看了很多大佬的博客,他们都很擅于总结自己的一年,并且也会将之发到自己的博客上,我感觉这样也挺好的。自己之前都是将这些总结放到本地存储,但这样有时写了一会就不想去写了,很容易虎头蛇尾。因此我决定以后可以将一些总结,感触什么的放到博客里,以此来监督自己一直坚持下去~</p> + + + + + +
+ + + [GO] — 解析 GOROOT、GOPATH 以及 ubuntu 中构建 golang 项目 + + https://crisescode.github.io/blog/2020/12/27/GO-%E2%80%94-%E8%A7%A3%E6%9E%90-GOROOT%E3%80%81GOPATH-%E4%BB%A5%E5%8F%8A-UBUNTU-%E4%B8%AD%E6%9E%84%E5%BB%BA-golang-%E9%A1%B9%E7%9B%AE/ + 2020-12-27T08:26:31.000Z + 2024-09-04T14:46:05.630Z + + + + + + + + + + + + + + + + + [GO] golang学习之interface接口 + + https://crisescode.github.io/blog/2020/12/26/GO-%E2%80%94-Golang%E5%AD%A6%E4%B9%A0%E4%B9%8Binterface%E6%8E%A5%E5%8F%A3/ + 2020-12-26T14:17:21.000Z + 2024-09-04T14:46:05.630Z + + + + + + + + + + + + + + + [Kubernetes] 认识一下Kubernetes + + https://crisescode.github.io/blog/2020/10/29/Kubernetes-%E8%AE%A4%E8%AF%86%E4%B8%80%E4%B8%8BKubernetes/ + 2020-10-29T14:20:45.000Z + 2024-09-04T14:46:05.646Z + + 有哪些组件

Kubernetes 集群分为两个部分:

  • Kubernetes 控制平面
  • (工作)节点

其中控制平面的组件有:

  • Etcd 分布式持久化存储
  • API Server
  • Kube Scheduler
  • Kube Controller

运行容器任务依赖于每个工作节点上运行的组件,包括:

  • Kubelet
  • Kubelet 服务代理(kube proxy)
  • 容器运行时(docker,rkt,containerd或者其他)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
class Solution:
# 返回[a,b] 其中ab是出现一次的两个数字
def FindNumsAppearOnce(self, array):
# write code here
if array is None:
return

hash_map = {}
for num in array:
if num in hash_map:
hash_map[num] += 1
else:
hash_map[num] = 1

res = [num for num in hash_map.keys() if hash_map[num] == 1]
return res

代码测试:

1
2
3
4
5
if __name__ == "__main__":
print(Solution().FindNumsAppearOnce([2, 3, 1, 5, 1, 3, 6, 11, 6, 0, 11, 5]))

>>> [2, 0]

]]>
+ + + + <h3 id="JZ64-滑动窗口的最大值"><a href="#JZ64-滑动窗口的最大值" class="headerlink" title="JZ64 滑动窗口的最大值"></a>JZ64 滑动窗口的最大值</h3><p><strong>题目描述:</strong></p> +<blockquote> +<p>给定一个数组和滑动窗口的大小,找出所有滑动窗口里数值的最大值。例如,如果输入数组{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个:<br>{[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},<br>{2,3,4,2,[6,2,5],1}, {2,3,4,2,6,[2,5,1]}。</p> +</blockquote> +<p>这道题其实是昨天最后一道题<a href="http://localhost:4000/blog/2020/07/19/%E5%89%91%E6%8C%87offer-%E7%AC%AC%E4%B8%83%E5%A4%A9/"><code>JZ60</code></a>的升级版,其实也就是层次遍历二叉树(BFS)。层次遍历思想可以参见上一道题,只是此题需要结合二叉树的深度<code>depth</code>进行解题。在每次需要打印的地方,当深度<code>depth</code>对2取余,为0则从左到右打印,为1则反转打印。</p> +<p><strong>解法思路:</strong></p> +<figure class="highlight fortran"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><code class="hljs fortran"><span class="hljs-keyword">class</span> Solution:<br> def maxInWindows(self, num, <span class="hljs-built_in">size</span>):<br> # <span class="hljs-built_in">write</span> code here<br> <span class="hljs-keyword">if</span> num is <span class="hljs-keyword">None</span> or <span class="hljs-built_in">size</span> &lt;= <span class="hljs-number">0</span>:<br> <span class="hljs-keyword">return</span> []<br><br> max_list = []<br> for i <span class="hljs-keyword">in</span> <span class="hljs-built_in">range</span>(len(num) - <span class="hljs-built_in">size</span> + <span class="hljs-number">1</span>):<br> range_ = num[i: i+<span class="hljs-built_in">size</span>]<br> max_list.append(<span class="hljs-built_in">max</span>(range_))<br> <span class="hljs-keyword">return</span> max_list<br></code></pre></td></tr></table></figure> +<p><strong>代码测试:</strong></p> +<figure class="highlight stylus"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><code class="hljs stylus"><span class="hljs-keyword">if</span> __name__ == <span class="hljs-string">&quot;__main__&quot;</span>:<br> <span class="hljs-built_in">print</span>(<span class="hljs-built_in">Solution</span>()<span class="hljs-selector-class">.maxInWindows</span>(<span class="hljs-selector-attr">[2, 3, 4, 2, 6, 2, 5, 1]</span>, <span class="hljs-number">2</span>))<br><br>&gt;&gt;&gt; <span class="hljs-selector-attr">[3, 4, 4, 6, 6, 5, 5]</span><br></code></pre></td></tr></table></figure> + + + + + + + + + +
+ + + 剑指offer 第八天 + + https://crisescode.github.io/blog/2020/07/20/%E5%89%91%E6%8C%87offer-%E7%AC%AC%E5%85%AB%E5%A4%A9/ + 2020-07-20T15:43:10.000Z + 2024-09-04T14:46:05.646Z + + JZ59 按之字形顺序打印二叉树

题目描述:

请实现一个函数按照之字形打印二叉树,即第一行按照从左到右的顺序打印,第二层按照从右至左的顺序打印,第三行按照从左到右的顺序打印,其他行以此类推。

解法思路:
这道题其实是昨天最后一道题JZ60的升级版,其实也就是层次遍历二叉树(BFS)。层次遍历思想可以参见上一道题,只是此题需要结合二叉树的深度depth进行解题。在每次需要打印的地方,当深度depth对2取余,为0则从左到右打印,为1则反转打印。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
class TreeNode:
def __init__(self, x):
self.val = x
self.left = None
self.right = None


class Solution:
def Print(self, pRoot):
# write code here
if pRoot is None:
return []

depth = 0
node_queue = [pRoot]
res = []

while node_queue:
val = []
length = len(node_queue)
for i in range(length):
current = node_queue.pop(0)
val.append(current.val)

if current.left:
node_queue.append(current.left)

if current.right:
node_queue.append(current.right)

if depth % 2 == 0:
res.append(val)
else:
res.append(list(reversed(val)))

depth += 1

return res

代码测试:

1
2
3
4
5
6
7
8
9
10
11
12
if __name__ == "__main__":
root = TreeNode(0)
root.left = TreeNode(1)
root.right = TreeNode(2)
root.left.left = TreeNode(3)
root.left.right = TreeNode(4)
root.right.left = TreeNode(5)
root.right.left.left = TreeNode(6)

print(Solution().Print(root))

>>> [[0], [2, 1], [3, 4, 5], [6]]

JZ58 对称的二叉树

题目描述:

请实现一个函数,用来判断一棵二叉树是不是对称的。注意,如果一个二叉树同此二叉树的镜像是同样的,定义其为对称的。

解法思路:

1
2
3
4
5
6
7
8
9
10
11
class TreeNode:
def __init__(self, x):
self.val = x
self.left = None
self.right = None


class Solution:
def isSymmetrical(self, pRoot):
# write code here
pass

代码测试:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
if __name__ == "__main__":
num = 1
matrix = [[0 for i in range(4)] for j in range(4)]
for i in range(4):
for j in range(4):
matrix[i][j] = num
num += 1

print(Solution().printMatrix(matrix))
print(Solution().printMatrix([[1, 2], [3, 4], [5, 6], [7, 8], [9, 10]]))

>>> [1, 2, 3, 4, 8, 12, 16, 15, 14, 13, 9, 5, 6, 7, 11, 10]
[1, 2, 4, 6, 8, 10, 9, 7, 5, 3]


JZ38 二叉树的下一个结点

题目描述:

给定一个二叉树和其中的一个结点,请找出中序遍历顺序的下一个结点并且返回。注意,树中的结点不仅包含左右子结点,同时包含指向父结点的指针。

解法思路:

1
2
3
4
5
6
7
8
9
10
11
class TreeNode:
def __init__(self, x):
self.val = x
self.left = None
self.right = None


class Solution:
def GetNext(self, pNode):
# write code here
pass

代码测试:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
if __name__ == "__main__":
root = TreeNode(0)
root.left = TreeNode(1)
root.right = TreeNode(2)
root.left.left = TreeNode(3)
root.left.right = TreeNode(4)
root.right.left = TreeNode(5)
root.right.left.left = TreeNode(6)

print(Solution().TreeDepth(root))
print(Solution2().TreeDepth(root))

>>> 4
4

JZ38 平衡二叉树

题目描述:

输入一棵二叉树,判断该二叉树是否是平衡二叉树。

在这里,我们只需要考虑其平衡性,不需要考虑其是不是排序二叉树

解法思路:

1
2
3
4
5
6
7
8
9
10
11
12
class TreeNode:
def __init__(self, x):
self.val = x
self.left = None
self.right = None


class Solution:
def IsBalanced_Solution(self, pRoot):
# write code here
pass

代码测试:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
if __name__ == "__main__":
root = TreeNode(0)
root.left = TreeNode(1)
root.right = TreeNode(2)
root.left.left = TreeNode(3)
root.left.right = TreeNode(4)
root.right.left = TreeNode(5)
root.right.left.left = TreeNode(6)

print(Solution().TreeDepth(root))
print(Solution2().TreeDepth(root))

>>> 4
4
]]>
+ + + + <h3 id="JZ59-按之字形顺序打印二叉树"><a href="#JZ59-按之字形顺序打印二叉树" class="headerlink" title="JZ59 按之字形顺序打印二叉树"></a>JZ59 按之字形顺序打印二叉树</h3><p><strong>题目描述:</strong></p> +<blockquote> +<p>请实现一个函数按照之字形打印二叉树,即第一行按照从左到右的顺序打印,第二层按照从右至左的顺序打印,第三行按照从左到右的顺序打印,其他行以此类推。</p> +</blockquote> +<p><strong>解法思路:</strong><br>这道题其实是昨天最后一道题<a href="http://localhost:4000/blog/2020/07/19/%E5%89%91%E6%8C%87offer-%E7%AC%AC%E4%B8%83%E5%A4%A9/"><code>JZ60</code></a>的升级版,其实也就是层次遍历二叉树(BFS)。层次遍历思想可以参见上一道题,只是此题需要结合二叉树的深度<code>depth</code>进行解题。在每次需要打印的地方,当深度<code>depth</code>对2取余,为0则从左到右打印,为1则反转打印。</p> +<figure class="highlight vim"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br></pre></td><td class="code"><pre><code class="hljs vim">class TreeNode:<br> def __init__(self, <span class="hljs-keyword">x</span>):<br> self.val = <span class="hljs-keyword">x</span><br> self.<span class="hljs-keyword">left</span> = None<br> self.<span class="hljs-keyword">right</span> = None<br><br><br>class Solution:<br> def <span class="hljs-keyword">Print</span>(self, pRoot):<br> # <span class="hljs-keyword">write</span> code here<br> <span class="hljs-keyword">if</span> pRoot <span class="hljs-keyword">is</span> None:<br> <span class="hljs-keyword">return</span> []<br><br> depth = <span class="hljs-number">0</span><br> node_queue = [pRoot]<br> <span class="hljs-keyword">res</span> = []<br><br> <span class="hljs-keyword">while</span> node_queue:<br> val = []<br> length = <span class="hljs-built_in">len</span>(node_queue)<br> <span class="hljs-keyword">for</span> i in <span class="hljs-built_in">range</span>(length):<br> current = node_queue.<span class="hljs-keyword">pop</span>(<span class="hljs-number">0</span>)<br> val.<span class="hljs-keyword">append</span>(current.val)<br><br> <span class="hljs-keyword">if</span> current.<span class="hljs-keyword">left</span>:<br> node_queue.<span class="hljs-keyword">append</span>(current.<span class="hljs-keyword">left</span>)<br><br> <span class="hljs-keyword">if</span> current.<span class="hljs-keyword">right</span>:<br> node_queue.<span class="hljs-keyword">append</span>(current.<span class="hljs-keyword">right</span>)<br><br> <span class="hljs-keyword">if</span> depth % <span class="hljs-number">2</span> == <span class="hljs-number">0</span>:<br> <span class="hljs-keyword">res</span>.<span class="hljs-keyword">append</span>(val)<br> <span class="hljs-keyword">else</span>:<br> <span class="hljs-keyword">res</span>.<span class="hljs-keyword">append</span>(<span class="hljs-keyword">list</span>(reversed(val)))<br><br> depth += <span class="hljs-number">1</span><br><br> <span class="hljs-keyword">return</span> <span class="hljs-keyword">res</span><br></code></pre></td></tr></table></figure> +<p><strong>代码测试:</strong></p> +<figure class="highlight stylus"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><code class="hljs stylus"><span class="hljs-keyword">if</span> __name__ == <span class="hljs-string">&quot;__main__&quot;</span>:<br> root = <span class="hljs-built_in">TreeNode</span>(<span class="hljs-number">0</span>)<br> root<span class="hljs-selector-class">.left</span> = <span class="hljs-built_in">TreeNode</span>(<span class="hljs-number">1</span>)<br> root<span class="hljs-selector-class">.right</span> = <span class="hljs-built_in">TreeNode</span>(<span class="hljs-number">2</span>)<br> root<span class="hljs-selector-class">.left</span><span class="hljs-selector-class">.left</span> = <span class="hljs-built_in">TreeNode</span>(<span class="hljs-number">3</span>)<br> root<span class="hljs-selector-class">.left</span><span class="hljs-selector-class">.right</span> = <span class="hljs-built_in">TreeNode</span>(<span class="hljs-number">4</span>)<br> root<span class="hljs-selector-class">.right</span><span class="hljs-selector-class">.left</span> = <span class="hljs-built_in">TreeNode</span>(<span class="hljs-number">5</span>)<br> root<span class="hljs-selector-class">.right</span><span class="hljs-selector-class">.left</span><span class="hljs-selector-class">.left</span> = <span class="hljs-built_in">TreeNode</span>(<span class="hljs-number">6</span>)<br><br> <span class="hljs-built_in">print</span>(<span class="hljs-built_in">Solution</span>()<span class="hljs-selector-class">.Print</span>(root))<br><br>&gt;&gt;&gt; <span class="hljs-selector-attr">[[0]</span>, <span class="hljs-selector-attr">[2, 1]</span>, <span class="hljs-selector-attr">[3, 4, 5]</span>, <span class="hljs-selector-attr">[6]</span>]<br></code></pre></td></tr></table></figure> + + + + + + + + + +
+ + + 剑指offer 第七天 + + https://crisescode.github.io/blog/2020/07/19/%E5%89%91%E6%8C%87offer-%E7%AC%AC%E4%B8%83%E5%A4%A9/ + 2020-07-19T13:33:15.000Z + 2024-09-04T14:46:05.646Z + + JZ19 顺时针打印矩阵

题目描述:

输入一个矩阵,按照从外向里以顺时针的顺序依次打印出每一个数字,例如,如果输入如下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
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
class Solution:
# matrix类型为二维列表,需要返回列表
def printMatrix(self, matrix):
# write code here
top = 0
bottom = len(matrix)
left = 0
right = len(matrix[0])

res = []
# 判断是否越界
while top < bottom and left < right:
# 最上面一行,需向右打印
res.extend([matrix[top][c] for c in range(left, right)])
# 最右边一行,需向下打印
res.extend([matrix[r][right - 1] for r in range(top + 1, bottom)])
# 最下面一行,需向左打印
if bottom - top > 1:
res.extend([matrix[bottom - 1][c] for c in range(right - 2, left, -1)]) # 注意需要将右边那个值去除掉
# 最左边一行,需向上打印
if right - left > 1:
res.extend([matrix[r][left] for r in range(bottom - 1, top, -1)])

top += 1
bottom -= 1
left += 1
right -= 1

return res

代码测试:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
if __name__ == "__main__":
num = 1
matrix = [[0 for i in range(4)] for j in range(4)]
for i in range(4):
for j in range(4):
matrix[i][j] = num
num += 1

print(Solution().printMatrix(matrix))
print(Solution().printMatrix([[1, 2], [3, 4], [5, 6], [7, 8], [9, 10]]))

>>> [1, 2, 3, 4, 8, 12, 16, 15, 14, 13, 9, 5, 6, 7, 11, 10]
[1, 2, 4, 6, 8, 10, 9, 7, 5, 3]


JZ38 二叉树的深度

题目描述:

输入一棵二叉树,求该树的深度。从根结点到叶结点依次经过的结点(含根、叶结点)形成树的一条路径,最长路径的长度为树的深度。

解法思路:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
class TreeNode:
def __init__(self, x):
self.val = x
self.left = None
self.right = None


class Solution:
def TreeDepth(self, pRoot):
# write code here
if not pRoot:
return 0

x = pRoot

left = self.TreeDepth(pRoot.left)
right = self.TreeDepth(pRoot.right)

return max(left, right) + 1


class Solution2:
def TreeDepth(self, pRoot):
# write code here
if pRoot is None:
return 0
q = []
depth = 0
q.append(pRoot)
while len(q): # 队列为空时说明没有下一层
length = len(q)
for i in range(length): # 遍历层的每个节点看是否有子节点有则加入
current = q.pop(0) # current为当前遍历到的层中节点,取出,注意pop(-1)为默认,这里要pop(0),取出第一个,先入先出
if current.left:
q.append(current.left)
if current.right:
q.append(current.right)
depth += 1
return depth

代码测试:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
if __name__ == "__main__":
root = TreeNode(0)
root.left = TreeNode(1)
root.right = TreeNode(2)
root.left.left = TreeNode(3)
root.left.right = TreeNode(4)
root.right.left = TreeNode(5)
root.right.left.left = TreeNode(6)

print(Solution().TreeDepth(root))
print(Solution2().TreeDepth(root))

>>> 4
4

JZ60 把二叉树打印成多行

题目描述:

从上到下按层打印二叉树,同一层结点从左至右输出。每一层输出一行。

解法思路:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
class TreeNode:
def __init__(self, x):
self.val = x
self.left = None
self.right = None


class Solution:
# 返回二维列表[[1,2],[4,5]]
def Print(self, pRoot):
# write code here
if not pRoot:
return []

node_queue = [pRoot]
res = []
while node_queue:
val = []
length = len(node_queue)
for i in range(length):
current = node_queue.pop(0)
val.append(current.val)

if current.left:
node_queue.append(current.left)
if current.right:
node_queue.append(current.right)

res.append(val)

return res

代码测试:

1
2
3
4
5
6
7
8
9
10
11
12
if __name__ == "__main__":
root = TreeNode(8)
root.left = TreeNode(6)
root.right = TreeNode(10)
root.left.left = TreeNode(5)
root.left.right = TreeNode(7)
root.right.left = TreeNode(9)
root.right.right = TreeNode(11)

print(Solution().Print(root))

>>> [[8], [6, 10], [5, 7, 9, 11]]
]]>
+ + + + <h3 id="JZ19-顺时针打印矩阵"><a href="#JZ19-顺时针打印矩阵" class="headerlink" title="JZ19 顺时针打印矩阵"></a>JZ19 顺时针打印矩阵</h3><p><strong>题目描述:</strong></p> +<blockquote> +<p>输入一个矩阵,按照从外向里以顺时针的顺序依次打印出每一个数字,例如,如果输入如下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.</p> +</blockquote> +<p><strong>解法思路:</strong><br>这道题刚开始自己一看,就是想着设置一些索引位置,按照索引位置打印来打印不就行了。后来再认真读题,发现它输入的二维矩阵大小是变化的,不是固定大小,才发现自己的想法太<code>native</code>。</p> +<p>看了下讨论区,发现只是需要确定几个固定位置的索引值,便可以不管输入矩阵的大小,自适应的便能够确定顺时针打印每个位置的索引,然后再根据这个索引来打印矩阵就行,还真是巧妙。其实在确定好几个顶点的位置,也就相当于确定了方向,然后不管是顺时针还是逆时针,下次都可以方便的解题了。</p> + + + + + + + + + +
+ + + 剑指offer 第六天 + + https://crisescode.github.io/blog/2020/07/13/%E5%89%91%E6%8C%87offer-%E7%AC%AC%E5%85%AD%E5%A4%A9/ + 2020-07-13T12:43:55.000Z + 2024-09-04T14:46:05.646Z + + JZ6 旋转数组的最小数字

题目描述:

把一个数组最开始的若干个元素搬到数组的末尾,我们称之为数组的旋转。
输入一个非递减排序的数组的一个旋转,输出旋转数组的最小元素。
例如数组{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
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
class Solution:
def minNumberInRotateArray(self, rotateArray):
# write code here
if len(rotateArray) == 0:
return 0
left = 0
right = len(rotateArray) - 1
while left < right:
if rotateArray[left] < rotateArray[right]:
return rotateArray[left]

mid = (left + right) // 2
if rotateArray[mid] > rotateArray[left]:
left = mid + 1
elif rotateArray[mid] < rotateArray[right]:
right = mid
else:
left += 1

return rotateArray[left]

代码测试:

1
2
3
4
5
if __name__ == "__main__":
print(Solution().minNumberInRotateArray([1, 0, 1, 1, 1]))

>>> 0

JZ18 二叉树的镜像

题目描述:

操作给定的二叉树,将其变换为源二叉树的镜像。
二叉树的镜像定义如下:

 源二叉树    8   /  \  6   10 / \  / \5  7 9 11镜像二叉树     8   /  \  10   6 / \  / \11 9 7  5

解法思路:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
class TreeNode:
def __init__(self, x):
self.val = x
self.left = None
self.right = None


class Solution:
# 返回镜像树的根节点
def Mirror(self, root):
# write code here
if root is None:
return

root.left, root.right = \
self.Mirror(root.right), self.Mirror(root.left)

return root

def preOrder(self, root):
if root is None:
return

print(root.val, end=' ')
self.preOrder(root.left)
self.preOrder(root.right)

代码测试:

1
2
3
4
5
6
7
8
9
10
11
12
13
if __name__ == "__main__":
tree1 = TreeNode(8)
tree1.left = TreeNode(6)
tree1.right = TreeNode(10)
tree1.left.left = TreeNode(5)
tree1.left.right = TreeNode(7)
tree1.right.left = TreeNode(9)
tree1.right.right = TreeNode(11)

invert_tree = Solution().Mirror(tree1)
print(Solution().preOrder(invert_tree))

>>> 8 10 11 9 6 7 5 None

JZ23 二叉搜索树的后序遍历

题目描述:

输入一个整数数组,判断该数组是不是某二叉搜索树的后序遍历的结果。如果是则输出Yes,否则输出No。假设输入的数组的任意两个数字都互不相同。

解法思路:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
class Solution:
def VerifySquenceOfBST(self, sequence):
# write code here
if len(sequence) == 0:
return False

root = sequence[-1]
for index, value in enumerate(sequence):
if value > root:
break

for value in sequence[index: -1]:
if value < root:
return False

left = True
if index > 0:
left = self.VerifySquenceOfBST(sequence[:index])

right = True
if index < len(sequence) - 1:
right = self.VerifySquenceOfBST(sequence[index: -1])

return left and right

代码测试:

1
2
3
4
5
if __name__ == "__main__":
is_binary_tree = [1, 3, 5, 9, 12, 10, 7]
print(Solution().VerifySquenceOfBST(is_binary_tree))

>>> True

JZ67 剪绳子

题目描述:

给你一根长度为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

解法思路:

代码测试:

]]>
+ + + + <h3 id="JZ6-旋转数组的最小数字"><a href="#JZ6-旋转数组的最小数字" class="headerlink" title="JZ6 旋转数组的最小数字"></a>JZ6 旋转数组的最小数字</h3><p><strong>题目描述:</strong></p> +<blockquote> +<p>把一个数组最开始的若干个元素搬到数组的末尾,我们称之为数组的旋转。<br>输入一个非递减排序的数组的一个旋转,输出旋转数组的最小元素。<br>例如数组{3,4,5,1,2}为{1,2,3,4,5}的一个旋转,该数组的最小值为1。<br>NOTE:给出的所有元素都大于0,若数组大小为0,请返回0。</p> +</blockquote> +<p><strong>解法思路:</strong><br>这题主要是考察二分查找。<strong>二分查找</strong>,又叫折半查找。它的前提是线性表中的数据必须是有序的,线性表必须采用顺序存储。主要思想是:在有序表中,去中间记录作为比较对象,若给定值与中间记录的关键字相等,则查找成功;若给定值小于中间记录的关键字,则在中间记录的左半区继续查找;若给定值大于中间记录的关键字,则在中间记录的右半区继续查找;不断重复上述过程,直至查找成功,或所有查找区域无记录,查找失败为止。</p> +<p>上面介绍了二分查找的主要思路,而本题难点在于找到中间值与谁进行比较? 再认真审下题,给定的是非递减排序的数组,也就是“平序”或升序。例如:<code>[1, 2, 3, 3, 3, 5, 6]</code>(“平序”),<code>[1, 2, 3, 4, 5, 6]</code>(升序)。然后再做旋转得到旋转数组<code>[3, 3, 5, 6, 1, 2, 3]</code>,<code>[4, 5, 6, 1, 2, 3]</code>,可以确定的是旋转后的数组<code>nums[0] &gt;= nums[-1]</code>恒成立。</p> +<p>这样也就得到了<code>nums[mid]</code>与哪个值进行比较了,当然是:</p> +<ul> +<li><code>nums[mid] &gt; nums[left]</code> , 这个时候 <code>left = mid + 1</code></li> +<li><code>nums[mid] &lt; nums[right]</code>, 这个时候 <code>right = mid</code></li> +<li><code>nums[mid] = nums[right]</code>, 这个时候 <code>left += 1</code></li> +</ul> +<p>这里可以一定意义上认为<code>nums[left]</code>与<code>nums[right]</code>近似相等,这样便于理解。</p> +<blockquote> +<p>注: 以上<code>nums</code>代表传入的旋转数组,<code>left</code>指数组的第一个数,<code>right</code>指数组末尾的数,<code>mid</code>指数组中间位置的数。</p> +</blockquote> + + + + + + + + + +
+ +
diff --git a/categories/AI/index.html b/categories/AI/index.html new file mode 100644 index 0000000..1ecc952 --- /dev/null +++ b/categories/AI/index.html @@ -0,0 +1,444 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 分类 - AI - LuckyCrise + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ + + + + + +
+ +
+ +
+ + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git "a/categories/AI/\346\250\241\345\236\213\351\203\250\347\275\262/index.html" "b/categories/AI/\346\250\241\345\236\213\351\203\250\347\275\262/index.html" new file mode 100644 index 0000000..1ef1851 --- /dev/null +++ "b/categories/AI/\346\250\241\345\236\213\351\203\250\347\275\262/index.html" @@ -0,0 +1,444 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 分类 - 模型部署 - LuckyCrise + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ + + + + + +
+ +
+ +
+ + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/categories/GO/index.html b/categories/GO/index.html new file mode 100644 index 0000000..fc2fbe1 --- /dev/null +++ b/categories/GO/index.html @@ -0,0 +1,453 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 分类 - GO - LuckyCrise + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ + + + + + +
+ +
+ +
+ + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/categories/Kubernetes/index.html b/categories/Kubernetes/index.html new file mode 100644 index 0000000..82f149a --- /dev/null +++ b/categories/Kubernetes/index.html @@ -0,0 +1,459 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 分类 - Kubernetes - LuckyCrise + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ + + + + + +
+ +
+ +
+ + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/categories/NLP/index.html b/categories/NLP/index.html new file mode 100644 index 0000000..0f50de7 --- /dev/null +++ b/categories/NLP/index.html @@ -0,0 +1,444 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 分类 - NLP - LuckyCrise + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ + + + + + +
+ +
+ +
+ +
+
+ +
+
+ +
+
+
+
+ + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git "a/categories/NLP/\346\226\207\346\234\254\345\210\206\347\261\273/index.html" "b/categories/NLP/\346\226\207\346\234\254\345\210\206\347\261\273/index.html" new file mode 100644 index 0000000..4525d8d --- /dev/null +++ "b/categories/NLP/\346\226\207\346\234\254\345\210\206\347\261\273/index.html" @@ -0,0 +1,438 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 分类 - 文本分类 - LuckyCrise + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ + + + + + +
+ +
+ +
+ +
+
+ +
+
+
+ + +
+

共计 1 篇文章

+
+ + + + +

2020

+ + + +
NLP(1)文本分类知识梳理
+
+ +
+ + + + + +
+
+
+
+
+ + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git "a/categories/NLP/\346\226\207\346\234\254\347\224\237\346\210\220/index.html" "b/categories/NLP/\346\226\207\346\234\254\347\224\237\346\210\220/index.html" new file mode 100644 index 0000000..8ede2e8 --- /dev/null +++ "b/categories/NLP/\346\226\207\346\234\254\347\224\237\346\210\220/index.html" @@ -0,0 +1,438 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 分类 - 文本生成 - LuckyCrise + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ + + + + + +
+ +
+ +
+ +
+
+ +
+
+
+ + +
+

共计 1 篇文章

+
+ + + + +

2020

+ + + +
[NLP] 文本摘要之PGN指针生成网络
+
+ +
+ + + + + +
+
+
+
+
+ + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/categories/Python/index.html b/categories/Python/index.html new file mode 100644 index 0000000..a97e9c7 --- /dev/null +++ b/categories/Python/index.html @@ -0,0 +1,444 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 分类 - Python - LuckyCrise + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ + + + + + +
+ +
+ +
+ +
+
+ +
+
+
+ + + + + + + + +
+
+
+
+
+ + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/categories/index.html b/categories/index.html new file mode 100644 index 0000000..2168b40 --- /dev/null +++ b/categories/index.html @@ -0,0 +1,1031 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 分类 - LuckyCrise + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ + + + + + +
+ +
+ +
+ +
+
+ +
+
+
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + 2 + + +
+ + + + +
+ + +
+ + + + + + + + + + + + + + +
+
+ + + + + + + + + + + +
+ + +
+
+
+
+
+ + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git "a/categories/\345\210\267\351\242\230/index.html" "b/categories/\345\210\267\351\242\230/index.html" new file mode 100644 index 0000000..89fb669 --- /dev/null +++ "b/categories/\345\210\267\351\242\230/index.html" @@ -0,0 +1,498 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 分类 - 刷题 - LuckyCrise + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ + + + + + +
+ +
+ +
+ + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git "a/categories/\345\210\267\351\242\230/leetcode/index.html" "b/categories/\345\210\267\351\242\230/leetcode/index.html" new file mode 100644 index 0000000..04d35b7 --- /dev/null +++ "b/categories/\345\210\267\351\242\230/leetcode/index.html" @@ -0,0 +1,438 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 分类 - leetcode - LuckyCrise + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ + + + + + +
+ +
+ +
+ +
+
+ +
+
+
+ + +
+

共计 1 篇文章

+
+ + + + +

2020

+ + + +
[LeetCode] 数据结构之树
+
+ +
+ + + + + +
+
+
+
+
+ + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git "a/categories/\345\210\267\351\242\230/page/2/index.html" "b/categories/\345\210\267\351\242\230/page/2/index.html" new file mode 100644 index 0000000..b4acb0e --- /dev/null +++ "b/categories/\345\210\267\351\242\230/page/2/index.html" @@ -0,0 +1,450 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 分类 - 刷题 - LuckyCrise + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ + + + + + +
+ +
+ +
+ +
+
+ +
+
+
+ + +
+

共计 12 篇文章

+
+ + + + +

2020

+ + + +
剑指offer 第二天
+
+ + + + +
剑指offer 第一天
+
+ +
+ + + + + + + +
+
+
+
+
+ + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git "a/categories/\346\267\261\345\272\246\345\255\246\344\271\240\346\241\206\346\236\266/index.html" "b/categories/\346\267\261\345\272\246\345\255\246\344\271\240\346\241\206\346\236\266/index.html" new file mode 100644 index 0000000..bebe35e --- /dev/null +++ "b/categories/\346\267\261\345\272\246\345\255\246\344\271\240\346\241\206\346\236\266/index.html" @@ -0,0 +1,438 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 分类 - 深度学习框架 - LuckyCrise + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ + + + + + +
+ +
+ +
+ +
+
+ +
+
+
+ + +
+

共计 1 篇文章

+
+ + + + +

2020

+ + + +
分布式训练之PyTorch
+
+ +
+ + + + + +
+
+
+
+
+ + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/css/gitalk.css b/css/gitalk.css new file mode 100644 index 0000000..a268f1d --- /dev/null +++ b/css/gitalk.css @@ -0,0 +1,546 @@ +@font-face { + font-family: octicons-link; + src: url(data:font/woff;charset=utf-8;base64,d09GRgABAAAAAAZwABAAAAAACFQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABEU0lHAAAGaAAAAAgAAAAIAAAAAUdTVUIAAAZcAAAACgAAAAoAAQAAT1MvMgAAAyQAAABJAAAAYFYEU3RjbWFwAAADcAAAAEUAAACAAJThvmN2dCAAAATkAAAABAAAAAQAAAAAZnBnbQAAA7gAAACyAAABCUM+8IhnYXNwAAAGTAAAABAAAAAQABoAI2dseWYAAAFsAAABPAAAAZwcEq9taGVhZAAAAsgAAAA0AAAANgh4a91oaGVhAAADCAAAABoAAAAkCA8DRGhtdHgAAAL8AAAADAAAAAwGAACfbG9jYQAAAsAAAAAIAAAACABiATBtYXhwAAACqAAAABgAAAAgAA8ASm5hbWUAAAToAAABQgAAAlXu73sOcG9zdAAABiwAAAAeAAAAME3QpOBwcmVwAAAEbAAAAHYAAAB/aFGpk3jaTY6xa8JAGMW/O62BDi0tJLYQincXEypYIiGJjSgHniQ6umTsUEyLm5BV6NDBP8Tpts6F0v+k/0an2i+itHDw3v2+9+DBKTzsJNnWJNTgHEy4BgG3EMI9DCEDOGEXzDADU5hBKMIgNPZqoD3SilVaXZCER3/I7AtxEJLtzzuZfI+VVkprxTlXShWKb3TBecG11rwoNlmmn1P2WYcJczl32etSpKnziC7lQyWe1smVPy/Lt7Kc+0vWY/gAgIIEqAN9we0pwKXreiMasxvabDQMM4riO+qxM2ogwDGOZTXxwxDiycQIcoYFBLj5K3EIaSctAq2kTYiw+ymhce7vwM9jSqO8JyVd5RH9gyTt2+J/yUmYlIR0s04n6+7Vm1ozezUeLEaUjhaDSuXHwVRgvLJn1tQ7xiuVv/ocTRF42mNgZGBgYGbwZOBiAAFGJBIMAAizAFoAAABiAGIAznjaY2BkYGAA4in8zwXi+W2+MjCzMIDApSwvXzC97Z4Ig8N/BxYGZgcgl52BCSQKAA3jCV8CAABfAAAAAAQAAEB42mNgZGBg4f3vACQZQABIMjKgAmYAKEgBXgAAeNpjYGY6wTiBgZWBg2kmUxoDA4MPhGZMYzBi1AHygVLYQUCaawqDA4PChxhmh/8ODDEsvAwHgMKMIDnGL0x7gJQCAwMAJd4MFwAAAHjaY2BgYGaA4DAGRgYQkAHyGMF8NgYrIM3JIAGVYYDT+AEjAwuDFpBmA9KMDEwMCh9i/v8H8sH0/4dQc1iAmAkALaUKLgAAAHjaTY9LDsIgEIbtgqHUPpDi3gPoBVyRTmTddOmqTXThEXqrob2gQ1FjwpDvfwCBdmdXC5AVKFu3e5MfNFJ29KTQT48Ob9/lqYwOGZxeUelN2U2R6+cArgtCJpauW7UQBqnFkUsjAY/kOU1cP+DAgvxwn1chZDwUbd6CFimGXwzwF6tPbFIcjEl+vvmM/byA48e6tWrKArm4ZJlCbdsrxksL1AwWn/yBSJKpYbq8AXaaTb8AAHja28jAwOC00ZrBeQNDQOWO//sdBBgYGRiYWYAEELEwMTE4uzo5Zzo5b2BxdnFOcALxNjA6b2ByTswC8jYwg0VlNuoCTWAMqNzMzsoK1rEhNqByEyerg5PMJlYuVueETKcd/89uBpnpvIEVomeHLoMsAAe1Id4AAAAAAAB42oWQT07CQBTGv0JBhagk7HQzKxca2sJCE1hDt4QF+9JOS0nbaaYDCQfwCJ7Au3AHj+LO13FMmm6cl7785vven0kBjHCBhfpYuNa5Ph1c0e2Xu3jEvWG7UdPDLZ4N92nOm+EBXuAbHmIMSRMs+4aUEd4Nd3CHD8NdvOLTsA2GL8M9PODbcL+hD7C1xoaHeLJSEao0FEW14ckxC+TU8TxvsY6X0eLPmRhry2WVioLpkrbp84LLQPGI7c6sOiUzpWIWS5GzlSgUzzLBSikOPFTOXqly7rqx0Z1Q5BAIoZBSFihQYQOOBEdkCOgXTOHA07HAGjGWiIjaPZNW13/+lm6S9FT7rLHFJ6fQbkATOG1j2OFMucKJJsxIVfQORl+9Jyda6Sl1dUYhSCm1dyClfoeDve4qMYdLEbfqHf3O/AdDumsjAAB42mNgYoAAZQYjBmyAGYQZmdhL8zLdDEydARfoAqIAAAABAAMABwAKABMAB///AA8AAQAAAAAAAAAAAAAAAAABAAAAAA==) format('woff'); +} +/* variables */ +/* functions & mixins */ +/* variables - calculated */ +/* styles */ +.gt-container { + -webkit-box-sizing: border-box; + box-sizing: border-box; + font-size: 16px; + /* loader */ + /* error */ + /* initing */ + /* no int */ + /* link */ + /* meta */ + /* popup */ + /* header */ + /* comments */ + /* comment */ +} +.gt-container * { + -webkit-box-sizing: border-box; + box-sizing: border-box; +} +.gt-container a { + color: #6190e8; +} +.gt-container a:hover { + color: #81a6ed; + border-color: #81a6ed; +} +.gt-container a.is--active { + color: #333; + cursor: default !important; +} +.gt-container a.is--active:hover { + color: #333; +} +.gt-container .hide { + display: none !important; +} +.gt-container .gt-svg { + display: inline-block; + width: 1em; + height: 1em; + vertical-align: sub; +} +.gt-container .gt-svg svg { + width: 100%; + height: 100%; + fill: #6190e8; +} +.gt-container .gt-ico { + display: inline-block; +} +.gt-container .gt-ico-text { + margin-left: 0.3125em; +} +.gt-container .gt-ico-github { + width: 100%; + height: 100%; +} +.gt-container .gt-ico-github .gt-svg { + width: 100%; + height: 100%; +} +.gt-container .gt-ico-github svg { + fill: inherit; +} +.gt-container .gt-spinner { + position: relative; +} +.gt-container .gt-spinner::before { + content: ''; + -webkit-box-sizing: border-box; + box-sizing: border-box; + position: absolute; + top: 3px; + width: 0.75em; + height: 0.75em; + margin-top: -0.1875em; + margin-left: -0.375em; + border-radius: 50%; + border: 1px solid #fff; + border-top-color: #6190e8; + -webkit-animation: gt-kf-rotate 0.6s linear infinite; + animation: gt-kf-rotate 0.6s linear infinite; +} +.gt-container .gt-loader { + position: relative; + border: 1px solid #999; + -webkit-animation: ease gt-kf-rotate 1.5s infinite; + animation: ease gt-kf-rotate 1.5s infinite; + display: inline-block; + font-style: normal; + width: 1.75em; + height: 1.75em; + line-height: 1.75em; + border-radius: 50%; +} +.gt-container .gt-loader:before { + content: ''; + position: absolute; + display: block; + top: 0; + left: 50%; + margin-top: -0.1875em; + margin-left: -0.1875em; + width: 0.375em; + height: 0.375em; + background-color: #999; + border-radius: 50%; +} +.gt-container .gt-avatar { + display: inline-block; + width: 3.125em; + height: 3.125em; +} +@media (max-width: 479px) { + .gt-container .gt-avatar { + width: 2em; + height: 2em; + } +} +.gt-container .gt-avatar img { + width: 100%; + height: auto; + border-radius: 3px; +} +.gt-container .gt-avatar-github { + width: 3em; + height: 3em; +} +@media (max-width: 479px) { + .gt-container .gt-avatar-github { + width: 1.875em; + height: 1.875em; + } +} +.gt-container .gt-btn { + padding: 0.75em 1.25em; + display: inline-block; + line-height: 1; + text-decoration: none; + white-space: nowrap; + cursor: pointer; + border: 1px solid #6190e8; + border-radius: 5px; + background-color: #6190e8; + color: #fff; + outline: none; + font-size: 0.75em; +} +.gt-container .gt-btn-text { + font-weight: 400; +} +.gt-container .gt-btn-loading { + position: relative; + margin-left: 0.5em; + display: inline-block; + width: 0.75em; + height: 1em; + vertical-align: top; +} +.gt-container .gt-btn.is--disable { + cursor: not-allowed; + opacity: 0.5; +} +.gt-container .gt-btn-login { + margin-right: 0; +} +.gt-container .gt-btn-preview { + background-color: #fff; + color: #6190e8; +} +.gt-container .gt-btn-preview:hover { + background-color: #f2f2f2; + border-color: #81a6ed; +} +.gt-container .gt-btn-public:hover { + background-color: #81a6ed; + border-color: #81a6ed; +} +.gt-container .gt-error { + text-align: center; + margin: 0.625em; + color: #ff3860; +} +.gt-container .gt-initing { + padding: 1.25em 0; + text-align: center; +} +.gt-container .gt-initing-text { + margin: 0.625em auto; + font-size: 92%; +} +.gt-container .gt-no-init { + padding: 1.25em 0; + text-align: center; +} +.gt-container .gt-link { + border-bottom: 1px dotted #6190e8; +} +.gt-container .gt-link-counts, +.gt-container .gt-link-project { + text-decoration: none; +} +.gt-container .gt-meta { + margin: 1.25em 0; + padding: 1em 0; + position: relative; + border-bottom: 1px solid #e9e9e9; + font-size: 1em; + position: relative; + z-index: 10; +} +.gt-container .gt-meta:before, +.gt-container .gt-meta:after { + content: " "; + display: table; +} +.gt-container .gt-meta:after { + clear: both; +} +.gt-container .gt-counts { + margin: 0 0.625em 0 0; +} +.gt-container .gt-user { + float: right; + margin: 0; + font-size: 92%; +} +.gt-container .gt-user-pic { + width: 16px; + height: 16px; + vertical-align: top; + margin-right: 0.5em; +} +.gt-container .gt-user-inner { + display: inline-block; + cursor: pointer; +} +.gt-container .gt-user .gt-ico { + margin: 0 0 0 0.3125em; +} +.gt-container .gt-user .gt-ico svg { + fill: inherit; +} +.gt-container .gt-user .is--poping .gt-ico svg { + fill: #6190e8; +} +.gt-container .gt-version { + color: #a1a1a1; + margin-left: 0.375em; +} +.gt-container .gt-copyright { + margin: 0 0.9375em 0.5em; + border-top: 1px solid #e9e9e9; + padding-top: 0.5em; +} +.gt-container .gt-popup { + position: absolute; + right: 0; + top: 2.375em; + background: #fff; + display: inline-block; + border: 1px solid #e9e9e9; + padding: 0.625em 0; + font-size: 0.875em; + letter-spacing: 0.5px; +} +.gt-container .gt-popup .gt-action { + cursor: pointer; + display: block; + margin: 0.5em 0; + padding: 0 1.125em; + position: relative; + text-decoration: none; +} +.gt-container .gt-popup .gt-action.is--active:before { + content: ''; + width: 0.25em; + height: 0.25em; + background: #6190e8; + position: absolute; + left: 0.5em; + top: 0.4375em; +} +.gt-container .gt-header { + position: relative; + display: -webkit-box; + display: -ms-flexbox; + display: flex; +} +.gt-container .gt-header-comment { + -webkit-box-flex: 1; + -ms-flex: 1; + flex: 1; + margin-left: 1.25em; +} +@media (max-width: 479px) { + .gt-container .gt-header-comment { + margin-left: 0.875em; + } +} +.gt-container .gt-header-textarea { + padding: 0.75em; + display: block; + -webkit-box-sizing: border-box; + box-sizing: border-box; + width: 100%; + min-height: 5.125em; + max-height: 15em; + border-radius: 5px; + border: 1px solid rgba(0,0,0,0.1); + font-size: 0.875em; + word-wrap: break-word; + resize: vertical; + background-color: #f6f6f6; + outline: none; + -webkit-transition: all 0.25s ease; + transition: all 0.25s ease; +} +.gt-container .gt-header-textarea:hover { + background-color: #fbfbfb; +} +.gt-container .gt-header-preview { + padding: 0.75em; + border-radius: 5px; + border: 1px solid rgba(0,0,0,0.1); + background-color: #f6f6f6; +} +.gt-container .gt-header-controls { + position: relative; + margin: 0.75em 0 0; +} +.gt-container .gt-header-controls:before, +.gt-container .gt-header-controls:after { + content: " "; + display: table; +} +.gt-container .gt-header-controls:after { + clear: both; +} +@media (max-width: 479px) { + .gt-container .gt-header-controls { + margin: 0; + } +} +.gt-container .gt-header-controls-tip { + font-size: 0.875em; + color: #6190e8; + text-decoration: none; + vertical-align: sub; +} +@media (max-width: 479px) { + .gt-container .gt-header-controls-tip { + display: none; + } +} +.gt-container .gt-header-controls .gt-btn { + float: right; + margin-left: 1.25em; +} +@media (max-width: 479px) { + .gt-container .gt-header-controls .gt-btn { + float: none; + width: 100%; + margin: 0.75em 0 0; + } +} +.gt-container:after { + content: ''; + position: fixed; + bottom: 100%; + left: 0; + right: 0; + top: 0; + opacity: 0; +} +.gt-container.gt-input-focused { + position: relative; +} +.gt-container.gt-input-focused:after { + content: ''; + position: fixed; + bottom: 0%; + left: 0; + right: 0; + top: 0; + background: #000; + opacity: 0.6; + -webkit-transition: opacity 0.3s, bottom 0s; + transition: opacity 0.3s, bottom 0s; + z-index: 9999; +} +.gt-container.gt-input-focused .gt-header-comment { + z-index: 10000; +} +.gt-container .gt-comments { + padding-top: 1.25em; +} +.gt-container .gt-comments-null { + text-align: center; +} +.gt-container .gt-comments-controls { + margin: 1.25em 0; + text-align: center; +} +.gt-container .gt-comment { + position: relative; + padding: 0.625em 0; + display: -webkit-box; + display: -ms-flexbox; + display: flex; +} +.gt-container .gt-comment-content { + -webkit-box-flex: 1; + -ms-flex: 1; + flex: 1; + margin-left: 1.25em; + padding: 0.75em 1em; + background-color: #f9f9f9; + overflow: auto; + -webkit-transition: all ease 0.25s; + transition: all ease 0.25s; +} +.gt-container .gt-comment-content:hover { + -webkit-box-shadow: 0 0.625em 3.75em 0 #f4f4f4; + box-shadow: 0 0.625em 3.75em 0 #f4f4f4; +} +@media (max-width: 479px) { + .gt-container .gt-comment-content { + margin-left: 0.875em; + padding: 0.625em 0.75em; + } +} +.gt-container .gt-comment-header { + margin-bottom: 0.5em; + font-size: 0.875em; + position: relative; +} +.gt-container .gt-comment-block-1 { + float: right; + height: 1.375em; + width: 2em; +} +.gt-container .gt-comment-block-2 { + float: right; + height: 1.375em; + width: 4em; +} +.gt-container .gt-comment-username { + font-weight: 500; + color: #6190e8; + text-decoration: none; +} +.gt-container .gt-comment-username:hover { + text-decoration: underline; +} +.gt-container .gt-comment-text { + margin-left: 0.5em; + color: #a1a1a1; +} +.gt-container .gt-comment-date { + margin-left: 0.5em; + color: #a1a1a1; +} +.gt-container .gt-comment-like, +.gt-container .gt-comment-edit, +.gt-container .gt-comment-reply { + position: absolute; + height: 1.375em; +} +.gt-container .gt-comment-like:hover, +.gt-container .gt-comment-edit:hover, +.gt-container .gt-comment-reply:hover { + cursor: pointer; +} +.gt-container .gt-comment-like { + top: 0; + right: 2em; +} +.gt-container .gt-comment-edit, +.gt-container .gt-comment-reply { + top: 0; + right: 0; +} +.gt-container .gt-comment-body { + color: #333 !important; +} +.gt-container .gt-comment-body .email-hidden-toggle a { + display: inline-block; + height: 12px; + padding: 0 9px; + font-size: 12px; + font-weight: 600; + line-height: 6px; + color: #444d56; + text-decoration: none; + vertical-align: middle; + background: #dfe2e5; + border-radius: 1px; +} +.gt-container .gt-comment-body .email-hidden-toggle a:hover { + background-color: #c6cbd1; +} +.gt-container .gt-comment-body .email-hidden-reply { + display: none; + white-space: pre-wrap; +} +.gt-container .gt-comment-body .email-hidden-reply .email-signature-reply { + padding: 0 15px; + margin: 15px 0; + color: #586069; + border-left: 4px solid #dfe2e5; +} +.gt-container .gt-comment-body .email-hidden-reply.expanded { + display: block; +} +.gt-container .gt-comment-admin .gt-comment-content { + background-color: #f6f9fe; +} +@-webkit-keyframes gt-kf-rotate { + 0% { + -webkit-transform: rotate(0); + transform: rotate(0); + } + 100% { + -webkit-transform: rotate(360deg); + transform: rotate(360deg); + } +} +@keyframes gt-kf-rotate { + 0% { + -webkit-transform: rotate(0); + transform: rotate(0); + } + 100% { + -webkit-transform: rotate(360deg); + transform: rotate(360deg); + } +} diff --git a/css/highlight-dark.css b/css/highlight-dark.css new file mode 100644 index 0000000..9cae4a7 --- /dev/null +++ b/css/highlight-dark.css @@ -0,0 +1 @@ +pre code.hljs{display:block;overflow-x:auto;padding:1em}code.hljs{padding:3px 5px}.hljs{color:#ddd;background:#303030}.hljs-keyword,.hljs-link,.hljs-literal,.hljs-section,.hljs-selector-tag{color:#fff}.hljs-addition,.hljs-attribute,.hljs-built_in,.hljs-bullet,.hljs-name,.hljs-string,.hljs-symbol,.hljs-template-tag,.hljs-template-variable,.hljs-title,.hljs-type,.hljs-variable{color:#d88}.hljs-comment,.hljs-deletion,.hljs-meta,.hljs-quote{color:#979797}.hljs-doctag,.hljs-keyword,.hljs-literal,.hljs-name,.hljs-section,.hljs-selector-tag,.hljs-strong,.hljs-title,.hljs-type{font-weight:700}.hljs-emphasis{font-style:italic} diff --git a/css/highlight.css b/css/highlight.css new file mode 100644 index 0000000..96af284 --- /dev/null +++ b/css/highlight.css @@ -0,0 +1,10 @@ +pre code.hljs{display:block;overflow-x:auto;padding:1em}code.hljs{padding:3px 5px}/*! + Theme: GitHub + Description: Light theme as seen on github.com + Author: github.com + Maintainer: @Hirse + Updated: 2021-05-15 + + Outdated base version: https://github.com/primer/github-syntax-light + Current colors taken from GitHub's CSS +*/.hljs{color:#24292e;background:#fff}.hljs-doctag,.hljs-keyword,.hljs-meta .hljs-keyword,.hljs-template-tag,.hljs-template-variable,.hljs-type,.hljs-variable.language_{color:#d73a49}.hljs-title,.hljs-title.class_,.hljs-title.class_.inherited__,.hljs-title.function_{color:#6f42c1}.hljs-attr,.hljs-attribute,.hljs-literal,.hljs-meta,.hljs-number,.hljs-operator,.hljs-selector-attr,.hljs-selector-class,.hljs-selector-id,.hljs-variable{color:#005cc5}.hljs-meta .hljs-string,.hljs-regexp,.hljs-string{color:#032f62}.hljs-built_in,.hljs-symbol{color:#e36209}.hljs-code,.hljs-comment,.hljs-formula{color:#6a737d}.hljs-name,.hljs-quote,.hljs-selector-pseudo,.hljs-selector-tag{color:#22863a}.hljs-subst{color:#24292e}.hljs-section{color:#005cc5;font-weight:700}.hljs-bullet{color:#735c0f}.hljs-emphasis{color:#24292e;font-style:italic}.hljs-strong{color:#24292e;font-weight:700}.hljs-addition{color:#22863a;background-color:#f0fff4}.hljs-deletion{color:#b31d28;background-color:#ffeef0} diff --git a/css/main.css b/css/main.css new file mode 100644 index 0000000..b755b54 --- /dev/null +++ b/css/main.css @@ -0,0 +1,2097 @@ +.anchorjs-link { + text-decoration: none !important; + transition: opacity 0.2s ease-in-out; +} +.markdown-body h1:hover > .anchorjs-link, +h2:hover > .anchorjs-link, +h3:hover > .anchorjs-link, +h4:hover > .anchorjs-link, +h5:hover > .anchorjs-link, +h6:hover > .anchorjs-link { + opacity: 1; +} +.banner { + height: 100%; + position: relative; + overflow: hidden; + cursor: default; +} +.banner .mask { + position: absolute; + width: 100%; + height: 100%; + background-color: rgba(0,0,0,0.3); +} +.banner[parallax="true"] { + will-change: transform; + -webkit-transform-style: preserve-3d; + -webkit-backface-visibility: hidden; + transition: transform 0.05s ease-out; +} +@media (max-width: 100vh) { + .header-inner { + max-height: 100vw; + } + #board { + margin-top: -1rem !important; + } +} +@media (max-width: 79.99vh) { + .scroll-down-bar { + display: none; + } +} +#board { + position: relative; + margin-top: -2rem; + padding: 3rem 0; + background-color: var(--board-bg-color); + transition: background-color 0.2s ease-in-out; + border-radius: 0.5rem; + z-index: 3; + -webkit-box-shadow: 0 12px 15px 0 rgba(0,0,0,0.24), 0 17px 50px 0 rgba(0,0,0,0.19); + box-shadow: 0 12px 15px 0 rgba(0,0,0,0.24), 0 17px 50px 0 rgba(0,0,0,0.19); +} +.code-widget { + display: inline-block; + background-color: transparent; + font-size: 0.75rem; + line-height: 1; + font-weight: bold; + padding: 0.3rem 0.1rem 0.1rem 0.1rem; + position: absolute; + right: 0.45rem; + top: 0.15rem; + z-index: 1; +} +.code-widget-light { + color: #999; +} +.code-widget-dark { + color: #bababa; +} +.copy-btn { + cursor: pointer; + user-select: none; + -webkit-appearance: none; + outline: none; +} +.copy-btn > i { + font-size: 0.75rem !important; + font-weight: 400; + margin-right: 0.15rem; + opacity: 0; + transition: opacity 0.2s ease-in-out; +} +.markdown-body pre:hover > .copy-btn > i { + opacity: 0.9; +} +.markdown-body pre:hover > .copy-btn, +.markdown-body pre:not(:hover) > .copy-btn { + outline: none; +} +.license-box { + background-color: rgba(27,31,35,0.05); + transition: background-color 0.2s ease-in-out; + border-radius: 4px; + font-size: 0.9rem; + overflow: hidden; + padding: 1.25rem; + position: relative; + z-index: 1; +} +.license-box .license-icon { + position: absolute; + top: 50%; + left: 100%; +} +.license-box .license-icon::after { + content: "\e8e4"; + font-size: 12.5rem; + line-height: 1; + opacity: 0.1; + position: relative; + left: -0.85em; + bottom: 0.5em; + z-index: -1; +} +.license-box .license-title { + margin-bottom: 1rem; +} +.license-box .license-title div:nth-child(1) { + line-height: 1.2; + margin-bottom: 0.25rem; +} +.license-box .license-title div:nth-child(2) { + color: var(--sec-text-color); + font-size: 0.8rem; +} +.license-box .license-meta { + align-items: center; + display: flex; + flex-wrap: wrap; + justify-content: flex-start; +} +.license-box .license-meta .license-meta-item { + align-items: center; + justify-content: center; + margin-right: 1.5rem; +} +.license-box .license-meta .license-meta-item div:nth-child(1) { + color: var(--sec-text-color); + font-size: 0.8rem; + font-weight: normal; +} +.license-box .license-meta .license-meta-item i.iconfont { + font-size: 1rem; +} +@media (max-width: 575px) and (min-width: 425px) { + .license-box .license-meta .license-meta-item { + display: flex; + justify-content: flex-start; + flex-wrap: wrap; + font-size: 0.8rem; + flex: 0 0 50%; + max-width: 50%; + margin-right: 0; + } + .license-box .license-meta .license-meta-item div:nth-child(1) { + margin-right: 0.5rem; + } + .license-box .license-meta .license-meta-date { + order: -1; + } +} +@media (max-width: 424px) { + .license-box::after { + top: -65px; + } + .license-box .license-meta { + flex-direction: column; + align-items: flex-start; + } + .license-box .license-meta .license-meta-item { + display: flex; + flex-wrap: wrap; + font-size: 0.8rem; + } + .license-box .license-meta .license-meta-item div:nth-child(1) { + margin-right: 0.5rem; + } +} +.footer-inner { + padding: 3rem 0 1rem 0; + text-align: center; +} +.footer-inner > div:not(:first-child) { + margin: 0.25rem 0; + font-size: 0.85rem; +} +.footer-inner .statistics { + display: flex; + flex-direction: row; + justify-content: center; +} +.footer-inner .statistics > span { + flex: 1; + margin: 0 0.25rem; +} +.footer-inner .statistics > *:nth-last-child(2):first-child { + text-align: right; +} +.footer-inner .statistics > *:nth-last-child(2):first-child ~ * { + text-align: left; +} +.footer-inner .beian { + display: flex; + flex-direction: row; + justify-content: center; +} +.footer-inner .beian > * { + margin: 0 0.25rem; +} +.footer-inner .beian-police { + position: relative; + overflow: hidden; + display: inline-flex; + align-items: center; + justify-content: left; +} +.footer-inner .beian-police img { + margin-right: 3px; + width: 1rem; + height: 1rem; + margin-bottom: 0.1rem; +} +@media (max-width: 424px) { + .footer-inner .statistics { + flex-direction: column; + } + .footer-inner .statistics > *:nth-last-child(2):first-child { + text-align: center; + } + .footer-inner .statistics > *:nth-last-child(2):first-child ~ * { + text-align: center; + } + .footer-inner .beian { + flex-direction: column; + } + .footer-inner .beian .beian-police { + justify-content: center; + } + .footer-inner .beian > *:nth-last-child(2):first-child { + text-align: center; + } + .footer-inner .beian > *:nth-last-child(2):first-child ~ * { + text-align: center; + } +} +sup > a::before, +.footnote-text::before { + display: block; + content: ""; + margin-top: -5rem; + height: 5rem; + width: 1px; + visibility: hidden; +} +sup > a::before, +.footnote-text::before { + display: inline-block; +} +.footnote-item::before { + display: block; + content: ""; + margin-top: -5rem; + height: 5rem; + width: 1px; + visibility: hidden; +} +.footnote-list ol { + list-style-type: none; + counter-reset: sectioncounter; + padding-left: 0.5rem; + font-size: 0.95rem; +} +.footnote-list ol li:before { + font-family: "Helvetica Neue", monospace, "Monaco"; + content: "[" counter(sectioncounter) "]"; + counter-increment: sectioncounter; +} +.footnote-list ol li+li { + margin-top: 0.5rem; +} +.footnote-text { + padding-left: 0.5em; +} +.navbar { + background-color: transparent; + font-size: 0.875rem; + box-shadow: 0 2px 5px 0 rgba(0,0,0,0.16), 0 2px 10px 0 rgba(0,0,0,0.12); + -webkit-box-shadow: 0 2px 5px 0 rgba(0,0,0,0.16), 0 2px 10px 0 rgba(0,0,0,0.12); +} +.navbar .navbar-brand { + color: var(--navbar-text-color); +} +.navbar .navbar-toggler .animated-icon span { + background-color: var(--navbar-text-color); +} +.navbar .nav-item .nav-link { + display: block; + color: var(--navbar-text-color); + transition: color 0.2s ease-in-out, background-color 0.2s ease-in-out; +} +.navbar .nav-item .nav-link:hover { + color: var(--link-hover-color); +} +.navbar .nav-item .nav-link:focus { + color: var(--navbar-text-color); +} +.navbar .nav-item .nav-link i { + font-size: 0.875rem; +} +.navbar .navbar-toggler { + border-width: 0; + outline: 0; +} +.navbar.scrolling-navbar { + will-change: background, padding; + -webkit-transition: background 0.5s ease-in-out, padding 0.5s ease-in-out; + transition: background 0.5s ease-in-out, padding 0.5s ease-in-out; +} +@media (min-width: 600px) { + .navbar.scrolling-navbar { + padding-top: 12px; + padding-bottom: 12px; + } + .navbar.scrolling-navbar .navbar-nav > li { + -webkit-transition-duration: 1s; + transition-duration: 1s; + } +} +.navbar.scrolling-navbar.top-nav-collapse { + padding-top: 5px; + padding-bottom: 5px; +} +.navbar .dropdown-menu { + font-size: 0.875rem; + color: var(--navbar-text-color); + background-color: rgba(0,0,0,0.3); + border: none; + min-width: 8rem; + -webkit-transition: background 0.5s ease-in-out, padding 0.5s ease-in-out; + transition: background 0.5s ease-in-out, padding 0.5s ease-in-out; +} +@media (max-width: 991.98px) { + .navbar .dropdown-menu { + text-align: center; + } +} +.navbar .dropdown-item { + color: var(--navbar-text-color); +} +.navbar .dropdown-item:hover, +.navbar .dropdown-item:focus { + color: var(--link-hover-color); + background-color: rgba(0,0,0,0.1); +} +@media (min-width: 992px) { + .navbar .dropdown:hover > .dropdown-menu { + display: block; + } + .navbar .dropdown > .dropdown-toggle:active { + pointer-events: none; + } + .navbar .dropdown-menu { + top: 95%; + } +} +.navbar .animated-icon { + width: 30px; + height: 20px; + position: relative; + margin: 0; + -webkit-transform: rotate(0deg); + -moz-transform: rotate(0deg); + -o-transform: rotate(0deg); + transform: rotate(0deg); + -webkit-transition: 0.5s ease-in-out; + -moz-transition: 0.5s ease-in-out; + -o-transition: 0.5s ease-in-out; + transition: 0.5s ease-in-out; + cursor: pointer; +} +.navbar .animated-icon span { + display: block; + position: absolute; + height: 3px; + width: 100%; + border-radius: 9px; + opacity: 1; + left: 0; + -webkit-transform: rotate(0deg); + -moz-transform: rotate(0deg); + -o-transform: rotate(0deg); + transform: rotate(0deg); + -webkit-transition: 0.25s ease-in-out; + -moz-transition: 0.25s ease-in-out; + -o-transition: 0.25s ease-in-out; + transition: 0.25s ease-in-out; + background: #fff; +} +.navbar .animated-icon span:nth-child(1) { + top: 0; +} +.navbar .animated-icon span:nth-child(2) { + top: 10px; +} +.navbar .animated-icon span:nth-child(3) { + top: 20px; +} +.navbar .animated-icon.open span:nth-child(1) { + top: 11px; + -webkit-transform: rotate(135deg); + -moz-transform: rotate(135deg); + -o-transform: rotate(135deg); + transform: rotate(135deg); +} +.navbar .animated-icon.open span:nth-child(2) { + opacity: 0; + left: -60px; +} +.navbar .animated-icon.open span:nth-child(3) { + top: 11px; + -webkit-transform: rotate(-135deg); + -moz-transform: rotate(-135deg); + -o-transform: rotate(-135deg); + transform: rotate(-135deg); +} +.navbar .dropdown-collapse, +.top-nav-collapse, +.navbar-col-show { + background-color: var(--navbar-bg-color); +} +@media (max-width: 767px) { + .navbar { + font-size: 1rem; + line-height: 2.5rem; + } +} +.banner-text { + color: var(--subtitle-color); + max-width: calc(960px - 6rem); + width: 80%; + overflow-wrap: break-word; +} +@media (max-width: 767px) { + #subtitle, + .typed-cursor { + font-size: 1.5rem; + } +} +@media (max-width: 575px) { + .banner-text { + font-size: 0.9rem; + } + #subtitle, + .typed-cursor { + font-size: 1.35rem; + } +} +.modal-dialog .modal-content { + background-color: var(--board-bg-color); + border: 0; + border-radius: 0.125rem; + -webkit-box-shadow: 0 5px 11px 0 rgba(0,0,0,0.18), 0 4px 15px 0 rgba(0,0,0,0.15); + box-shadow: 0 5px 11px 0 rgba(0,0,0,0.18), 0 4px 15px 0 rgba(0,0,0,0.15); +} +.modal-dialog .modal-content .modal-header { + border-bottom-color: var(--line-color); + transition: border-bottom-color 0.2s ease-in-out; +} +.close { + color: var(--text-color); +} +.close:hover { + color: var(--link-hover-color); +} +.close:focus { + outline: 0; +} +.modal-dialog .modal-content .modal-header { + border-top-left-radius: 0.125rem; + border-top-right-radius: 0.125rem; + border-bottom: 1px solid #dee2e6; +} +.md-form { + position: relative; + margin-top: 1.5rem; + margin-bottom: 1.5rem; +} +.md-form input[type] { + -webkit-box-sizing: content-box; + box-sizing: content-box; + background-color: transparent; + border: none; + border-bottom: 1px solid #ced4da; + border-radius: 0; + outline: none; + -webkit-box-shadow: none; + box-shadow: none; + transition: border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out, -webkit-box-shadow 0.15s ease-in-out; +} +.md-form input[type]:focus:not([readonly]) { + border-bottom: 1px solid #4285f4; + -webkit-box-shadow: 0 1px 0 0 #4285f4; + box-shadow: 0 1px 0 0 #4285f4; +} +.md-form input[type]:focus:not([readonly]) + label { + color: #4285f4; +} +.md-form input[type].valid, +.md-form input[type]:focus.valid { + border-bottom: 1px solid #00c851; + -webkit-box-shadow: 0 1px 0 0 #00c851; + box-shadow: 0 1px 0 0 #00c851; +} +.md-form input[type].valid + label, +.md-form input[type]:focus.valid + label { + color: #00c851; +} +.md-form input[type].invalid, +.md-form input[type]:focus.invalid { + border-bottom: 1px solid #f44336; + -webkit-box-shadow: 0 1px 0 0 #f44336; + box-shadow: 0 1px 0 0 #f44336; +} +.md-form input[type].invalid + label, +.md-form input[type]:focus.invalid + label { + color: #f44336; +} +.md-form input[type].validate { + margin-bottom: 2.5rem; +} +.md-form input[type].form-control { + height: auto; + padding: 0.6rem 0 0.4rem 0; + margin: 0 0 0.5rem 0; + color: var(--text-color); + background-color: transparent; + border-radius: 0; +} +.md-form label { + font-size: 0.8rem; + position: absolute; + top: -1rem; + left: 0; + color: #757575; + cursor: text; + transition: color 0.2s ease-out; +} +.modal-open[style] { + padding-right: 0 !important; + overflow: auto; +} +.modal-open[style] #navbar[style] { + padding-right: 1rem !important; +} +#nprogress .bar { + height: 3px !important; + background-color: #29d !important; +} +#nprogress .peg { + box-shadow: 0 0 14px #29d, 0 0 8px #29d !important; +} +@media (max-width: 575px) { + #nprogress .bar { + display: none; + } +} +.noscript-warning { + background-color: #f55; + color: #fff; + font-family: sans-serif; + font-size: 1rem; + font-weight: bold; + position: fixed; + left: 0; + bottom: 0; + text-align: center; + width: 100%; + z-index: 99; +} +.pagination { + margin-top: 3rem; + justify-content: center; +} +.pagination .space { + align-self: flex-end; +} +.pagination .page-number, +.pagination .current, +.pagination .extend { + outline: 0; + border: 0; + background-color: transparent; + font-size: 0.9rem; + padding: 0.5rem 0.75rem; + line-height: 1.25; + border-radius: 0.125rem; +} +.pagination .page-number { + margin: 0 0.05rem; +} +.pagination .page-number:hover, +.pagination .current { + transition: background-color 0.2s ease-in-out; + background-color: var(--link-hover-bg-color); +} +.qr-trigger { + cursor: pointer; + position: relative; +} +.qr-trigger:hover .qr-img { + display: block; + transition: all 0.3s; +} +.qr-img { + max-width: 12rem; + position: absolute; + right: -5.25rem; + z-index: 99; + display: none; + border-radius: 0.2rem; + background-color: transparent; + box-shadow: 0 0 20px -5px rgba(158,158,158,0.2); +} +.scroll-down-bar { + position: absolute; + width: 100%; + height: 6rem; + text-align: center; + cursor: pointer; + bottom: 0; +} +.scroll-down-bar i.iconfont { + font-size: 2rem; + font-weight: bold; + display: inline-block; + position: relative; + padding-top: 2rem; + color: var(--subtitle-color); + transform: translateZ(0); + animation: scroll-down 1.5s infinite; +} +#scroll-top-button { + position: fixed; + z-index: 99; + background: var(--board-bg-color); + transition: background-color 0.2s ease-in-out, bottom 0.3s ease; + border-radius: 4px; + min-width: 40px; + min-height: 40px; + bottom: -60px; + outline: none; + display: flex; + display: -webkit-flex; + align-items: center; + box-shadow: 0 2px 5px 0 rgba(0,0,0,0.16), 0 2px 10px 0 rgba(0,0,0,0.12); +} +#scroll-top-button i { + font-size: 32px; + margin: auto; + color: var(--sec-text-color); +} +#scroll-top-button:hover i, +#scroll-top-button:active i { + animation-name: scroll-top; + animation-duration: 1s; + animation-delay: 0.1s; + animation-timing-function: ease-in-out; + animation-iteration-count: infinite; + animation-fill-mode: forwards; + animation-direction: alternate; +} +#local-search-result .search-list-title { + border-left: 3px solid #0d47a1; +} +#local-search-result .search-list-content { + padding: 0 1.25rem; +} +#local-search-result .search-word { + color: #ff4500; +} +#toc { + visibility: hidden; +} +.toc-header { + margin-bottom: 0.5rem; + font-weight: bold; + line-height: 1.2; +} +.toc-header, +.toc-header > i { + font-size: 1.25rem; +} +.toc-body { + max-height: 75vh; + overflow-y: auto; + overflow: -moz-scrollbars-none; + -ms-overflow-style: none; +} +.toc-body ol { + list-style: none; + padding-inline-start: 1rem; +} +.toc-body::-webkit-scrollbar { + display: none; +} +.tocbot-list { + position: relative; +} +.tocbot-list ol { + list-style: none; + padding-left: 1rem; +} +.tocbot-list a { + font-size: 0.95rem; +} +.tocbot-link { + color: var(--text-color); +} +.tocbot-active-link { + font-weight: bold; + color: var(--link-hover-color); +} +.tocbot-is-collapsed { + max-height: 0; +} +.tocbot-is-collapsible { + overflow: hidden; + transition: all 0.3s ease-in-out; +} +.toc-list-item { + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; +} +.toc-list-item.is-active-li::before { + height: 1rem; + margin: 0.25rem 0; + visibility: visible; +} +.toc-list-item::before { + width: 0.15rem; + height: 0.2rem; + position: absolute; + left: 0.25rem; + content: ""; + border-radius: 2px; + margin: 0.65rem 0; + background: var(--link-hover-color); + visibility: hidden; + transition: height 0.1s ease-in-out, margin 0.1s ease-in-out, visibility 0.1s ease-in-out; +} +.sidebar { + position: -webkit-sticky; + position: sticky; + top: 2rem; + padding: 3rem 0; +} +html { + font-size: 16px; + letter-spacing: 0.03em; +} +html, +body { + height: 100%; + font-family: system-ui;; + overflow-wrap: break-word; +} +body { + transition: color 0.2s ease-in-out, background-color 0.2s ease-in-out; + background-color: var(--body-bg-color); + color: var(--text-color); + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; +} +body a { + color: var(--text-color); + text-decoration: none; + cursor: pointer; + transition: color 0.2s ease-in-out, background-color 0.2s ease-in-out; +} +body a:hover { + color: var(--link-hover-color); + text-decoration: none; + transition: color 0.2s ease-in-out, background-color 0.2s ease-in-out; +} +code { + color: inherit; +} +table { + font-size: inherit; + color: var(--post-text-color); +} +img[lazyload] { + object-fit: cover; +} +*[align="left"] { + text-align: left; +} +*[align="center"] { + text-align: center; +} +*[align="right"] { + text-align: right; +} +::-webkit-scrollbar { + width: 6px; + height: 6px; +} +::-webkit-scrollbar-thumb { + background-color: var(--scrollbar-color); + border-radius: 6px; +} +::-webkit-scrollbar-thumb:hover { + background-color: var(--scrollbar-hover-color); +} +::-webkit-scrollbar-corner { + background-color: transparent; +} +label { + margin-bottom: 0; +} +i.iconfont { + font-size: 1em; + line-height: 1; +} +:root { + --color-mode: "light"; + --body-bg-color: #eee; + --board-bg-color: #fff; + --text-color: #3c4858; + --sec-text-color: #718096; + --post-text-color: #2c3e50; + --post-heading-color: #1a202c; + --post-link-color: #0366d6; + --link-hover-color: #30a9de; + --link-hover-bg-color: #f8f9fa; + --line-color: #eaecef; + --navbar-bg-color: #2f4154; + --navbar-text-color: #fff; + --subtitle-color: #fff; + --scrollbar-color: #c4c6c9; + --scrollbar-hover-color: #a6a6a6; + --button-bg-color: transparent; + --button-hover-bg-color: #f2f3f5; + --highlight-bg-color: #f6f8fa; + --inlinecode-bg-color: rgba(175,184,193,0.2); +} +@media (prefers-color-scheme: dark) { + :root { + --color-mode: "dark"; + } + :root:not([data-user-color-scheme]) { + --body-bg-color: #181c27; + --board-bg-color: #252d38; + --text-color: #c4c6c9; + --sec-text-color: #a7a9ad; + --post-text-color: #c4c6c9; + --post-heading-color: #c4c6c9; + --post-link-color: #1589e9; + --link-hover-color: #30a9de; + --link-hover-bg-color: #364151; + --line-color: #435266; + --navbar-bg-color: #1f3144; + --navbar-text-color: #d0d0d0; + --subtitle-color: #d0d0d0; + --scrollbar-color: #687582; + --scrollbar-hover-color: #9da8b3; + --button-bg-color: transparent; + --button-hover-bg-color: #46647e; + --highlight-bg-color: #303030; + --inlinecode-bg-color: rgba(99,110,123,0.4); + } + :root:not([data-user-color-scheme]) img { + -webkit-filter: brightness(0.9); + filter: brightness(0.9); + transition: filter 0.2s ease-in-out; + } + :root:not([data-user-color-scheme]) .license-box { + background-color: rgba(62,75,94,0.35); + transition: background-color 0.2s ease-in-out; + } + :root:not([data-user-color-scheme]) .gt-comment-admin .gt-comment-content { + background-color: transparent; + transition: background-color 0.2s ease-in-out; + } +} +[data-user-color-scheme="dark"] { + --body-bg-color: #181c27; + --board-bg-color: #252d38; + --text-color: #c4c6c9; + --sec-text-color: #a7a9ad; + --post-text-color: #c4c6c9; + --post-heading-color: #c4c6c9; + --post-link-color: #1589e9; + --link-hover-color: #30a9de; + --link-hover-bg-color: #364151; + --line-color: #435266; + --navbar-bg-color: #1f3144; + --navbar-text-color: #d0d0d0; + --subtitle-color: #d0d0d0; + --scrollbar-color: #687582; + --scrollbar-hover-color: #9da8b3; + --button-bg-color: transparent; + --button-hover-bg-color: #46647e; + --highlight-bg-color: #303030; + --inlinecode-bg-color: rgba(99,110,123,0.4); +} +[data-user-color-scheme="dark"] img { + -webkit-filter: brightness(0.9); + filter: brightness(0.9); + transition: filter 0.2s ease-in-out; +} +[data-user-color-scheme="dark"] .license-box { + background-color: rgba(62,75,94,0.35); + transition: background-color 0.2s ease-in-out; +} +[data-user-color-scheme="dark"] .gt-comment-admin .gt-comment-content { + background-color: transparent; + transition: background-color 0.2s ease-in-out; +} +.fade-in-up { + -webkit-animation-name: fade-in-up; + animation-name: fade-in-up; +} +.hidden-mobile { + display: block; +} +.visible-mobile { + display: none; +} +@media (max-width: 575px) { + .hidden-mobile { + display: none; + } + .visible-mobile { + display: block; + } +} +.nomargin-x { + margin-left: 0 !important; + margin-right: 0 !important; +} +.nopadding-x { + padding-left: 0 !important; + padding-right: 0 !important; +} +@media (max-width: 767px) { + .nopadding-x-md { + padding-left: 0 !important; + padding-right: 0 !important; + } +} +.flex-center { + display: -webkit-box; + display: -ms-flexbox; + display: flex; + -webkit-box-align: center; + -ms-flex-align: center; + align-items: center; + -webkit-box-pack: center; + -ms-flex-pack: center; + justify-content: center; + height: 100%; +} +.hover-with-bg { + display: inline-block; + line-height: 1; +} +.hover-with-bg:hover { + background-color: var(--link-hover-bg-color); + transition-duration: 0.2s; + transition-timing-function: ease-in-out; + border-radius: 0.2rem; +} +@-moz-keyframes fade-in-up { + from { + opacity: 0; + -webkit-transform: translate3d(0, 100%, 0); + transform: translate3d(0, 100%, 0); + } + to { + opacity: 1; + -webkit-transform: translate3d(0, 0, 0); + transform: translate3d(0, 0, 0); + } +} +@-webkit-keyframes fade-in-up { + from { + opacity: 0; + -webkit-transform: translate3d(0, 100%, 0); + transform: translate3d(0, 100%, 0); + } + to { + opacity: 1; + -webkit-transform: translate3d(0, 0, 0); + transform: translate3d(0, 0, 0); + } +} +@-o-keyframes fade-in-up { + from { + opacity: 0; + -webkit-transform: translate3d(0, 100%, 0); + transform: translate3d(0, 100%, 0); + } + to { + opacity: 1; + -webkit-transform: translate3d(0, 0, 0); + transform: translate3d(0, 0, 0); + } +} +@keyframes fade-in-up { + from { + opacity: 0; + -webkit-transform: translate3d(0, 100%, 0); + transform: translate3d(0, 100%, 0); + } + to { + opacity: 1; + -webkit-transform: translate3d(0, 0, 0); + transform: translate3d(0, 0, 0); + } +} +@-moz-keyframes scroll-down { + 0% { + opacity: 0.8; + top: 0; + } + 50% { + opacity: 0.4; + top: -1em; + } + 100% { + opacity: 0.8; + top: 0; + } +} +@-webkit-keyframes scroll-down { + 0% { + opacity: 0.8; + top: 0; + } + 50% { + opacity: 0.4; + top: -1em; + } + 100% { + opacity: 0.8; + top: 0; + } +} +@-o-keyframes scroll-down { + 0% { + opacity: 0.8; + top: 0; + } + 50% { + opacity: 0.4; + top: -1em; + } + 100% { + opacity: 0.8; + top: 0; + } +} +@keyframes scroll-down { + 0% { + opacity: 0.8; + top: 0; + } + 50% { + opacity: 0.4; + top: -1em; + } + 100% { + opacity: 0.8; + top: 0; + } +} +@-moz-keyframes scroll-top { + 0% { + -webkit-transform: translateY(0); + transform: translateY(0); + } + 50% { + -webkit-transform: translateY(-0.35rem); + transform: translateY(-0.35rem); + } + 100% { + -webkit-transform: translateY(0); + transform: translateY(0); + } +} +@-webkit-keyframes scroll-top { + 0% { + -webkit-transform: translateY(0); + transform: translateY(0); + } + 50% { + -webkit-transform: translateY(-0.35rem); + transform: translateY(-0.35rem); + } + 100% { + -webkit-transform: translateY(0); + transform: translateY(0); + } +} +@-o-keyframes scroll-top { + 0% { + -webkit-transform: translateY(0); + transform: translateY(0); + } + 50% { + -webkit-transform: translateY(-0.35rem); + transform: translateY(-0.35rem); + } + 100% { + -webkit-transform: translateY(0); + transform: translateY(0); + } +} +@keyframes scroll-top { + 0% { + -webkit-transform: translateY(0); + transform: translateY(0); + } + 50% { + -webkit-transform: translateY(-0.35rem); + transform: translateY(-0.35rem); + } + 100% { + -webkit-transform: translateY(0); + transform: translateY(0); + } +} +.index-card { + margin-bottom: 2.5rem; +} +.index-img img { + display: block; + width: 100%; + height: 10rem; + object-fit: cover; + box-shadow: 0 5px 11px 0 rgba(0,0,0,0.18), 0 4px 15px 0 rgba(0,0,0,0.15); + border-radius: 0.25rem; + background-color: transparent; +} +.index-info { + display: flex; + flex-direction: column; + justify-content: space-between; + padding-top: 0.5rem; + padding-bottom: 0.5rem; +} +.index-header { + color: var(--text-color); + font-size: 1.5rem; + font-weight: bold; + line-height: 1.4; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; + margin-bottom: 0.25rem; +} +.index-header .index-pin { + color: var(--text-color); + font-size: 1.5rem; + margin-right: 0.15rem; +} +.index-btm { + color: var(--sec-text-color); +} +.index-btm a { + color: var(--sec-text-color); +} +.index-excerpt { + color: var(--sec-text-color); + margin: 0.5rem 0 0.5rem 0; + height: calc(1.4rem * 3); + overflow: hidden; + display: flex; +} +.index-excerpt > div { + width: 100%; + line-height: 1.4rem; + word-break: break-word; + display: -webkit-box; + -webkit-box-orient: vertical; + -webkit-line-clamp: 3; +} +.index-excerpt__noimg { + height: auto; + max-height: calc(1.4rem * 3); +} +@media (max-width: 767px) { + .index-info { + padding-top: 1.25rem; + } + .index-header { + font-size: 1.25rem; + white-space: normal; + overflow: hidden; + word-break: break-word; + display: -webkit-box; + -webkit-box-orient: vertical; + -webkit-line-clamp: 2; + } + .index-header .index-pin { + font-size: 1.25rem; + } +} +#valine.v[data-class=v] .status-bar, +#valine.v[data-class=v] .veditor, +#valine.v[data-class=v] .vinput, +#valine.v[data-class=v] .vbtn, +#valine.v[data-class=v] p, +#valine.v[data-class=v] pre code { + color: var(--text-color); +} +#valine.v[data-class=v] .vinput::placeholder { + color: var(--sec-text-color); +} +#valine.v[data-class=v] .vicon { + fill: var(--text-color); +} +.gt-container .gt-comment-content:hover { + -webkit-box-shadow: none; + box-shadow: none; +} +.gt-container .gt-comment-body { + color: var(--text-color) !important; + transition: color 0.2s ease-in-out; +} +#remark-km423lmfdslkm34-back { + z-index: 1030; +} +#remark-km423lmfdslkm34-node { + z-index: 1031; +} +.markdown-body .highlight pre, +.markdown-body pre { + padding: 1.45rem 1rem; +} +.markdown-body pre code.hljs { + padding: 0; +} +.markdown-body pre[class*="language-"] { + padding-top: 1.45rem; + padding-bottom: 1.45rem; + padding-right: 1rem; + line-height: 1.5; + margin-bottom: 1rem; +} +.markdown-body .code-wrapper { + position: relative; + border-radius: 4px; + margin-bottom: 1rem; +} +.markdown-body .hljs, +.markdown-body .highlight pre, +.markdown-body .code-wrapper pre, +.markdown-body figure.highlight td.gutter { + transition: color 0.2s ease-in-out, background-color 0.2s ease-in-out; + background-color: var(--highlight-bg-color); +} +pre[class*=language-].line-numbers { + position: initial; +} +figure { + margin: 1rem 0; +} +figure.highlight { + position: relative; +} +figure.highlight table { + border: 0; + margin: 0; + width: auto; + border-radius: 4px; +} +figure.highlight td { + border: 0; + padding: 0; +} +figure.highlight tr { + border: 0; +} +figure.highlight td.code { + width: 100%; +} +figure.highlight td.gutter { + display: table-cell; + position: -webkit-sticky; + position: sticky; + left: 0; + z-index: 1; +} +figure.highlight td.gutter pre { + text-align: right; + padding: 0 0.75rem; + border-radius: initial; + border-right: 1px solid #999; +} +figure.highlight td.gutter pre span.line { + color: #999; +} +figure.highlight td.code > pre { + border-top-left-radius: 0; + border-bottom-left-radius: 0; +} +.markdown-body { + font-size: 1rem; + line-height: 1.6; + font-family: system-ui;; + margin-bottom: 2rem; + color: var(--post-text-color); +} +.markdown-body > h1, +.markdown-body h2 { + border-bottom-color: var(--line-color); +} +.markdown-body > h1, +.markdown-body h2, +.markdown-body h3, +.markdown-body h4, +.markdown-body h5, +.markdown-body h6 { + color: var(--post-heading-color); + transition: color 0.2s ease-in-out, border-bottom-color 0.2s ease-in-out; + font-weight: bold; + margin-bottom: 0.75em; + margin-top: 2em; +} +.markdown-body > h1::before, +.markdown-body h2::before, +.markdown-body h3::before, +.markdown-body h4::before, +.markdown-body h5::before, +.markdown-body h6::before { + display: block; + content: ""; + margin-top: -5rem; + height: 5rem; + width: 1px; + visibility: hidden; +} +.markdown-body > h1:focus, +.markdown-body h2:focus, +.markdown-body h3:focus, +.markdown-body h4:focus, +.markdown-body h5:focus, +.markdown-body h6:focus { + outline: none; +} +.markdown-body a { + color: var(--post-link-color); +} +.markdown-body strong { + font-weight: bold; +} +.markdown-body code { + tab-size: 4; + background-color: var(--inlinecode-bg-color); + transition: background-color 0.2s ease-in-out; +} +.markdown-body table tr { + background-color: var(--board-bg-color); + transition: background-color 0.2s ease-in-out; +} +.markdown-body table tr:nth-child(2n) { + background-color: var(--board-bg-color); + transition: background-color 0.2s ease-in-out; +} +.markdown-body table th, +.markdown-body table td { + border-color: var(--line-color); + transition: border-color 0.2s ease-in-out; +} +.markdown-body pre { + font-size: 85% !important; +} +.markdown-body pre .mermaid { + text-align: center; +} +.markdown-body pre .mermaid > svg { + min-width: 100%; +} +.markdown-body p > img, +.markdown-body p > a > img, +.markdown-body figure > img, +.markdown-body figure > a > img { + max-width: 90%; + margin: 1.5rem auto; + display: block; + box-shadow: 0 5px 11px 0 rgba(0,0,0,0.18), 0 4px 15px 0 rgba(0,0,0,0.15); + border-radius: 4px; + background-color: transparent; +} +.markdown-body blockquote { + color: var(--sec-text-color); +} +.markdown-body details { + cursor: pointer; +} +.markdown-body details summary { + outline: none; +} +hr, +.markdown-body hr { + background-color: initial; + border-top: 1px solid var(--line-color); + transition: border-top-color 0.2s ease-in-out; +} +.markdown-body hr { + height: 0; + margin: 2rem 0; +} +.markdown-body figcaption.image-caption { + font-size: 0.8rem; + color: var(--post-text-color); + opacity: 0.65; + line-height: 1; + margin: -0.75rem auto 2rem; + text-align: center; +} +.markdown-body figcaption:not(.image-caption) { + display: none; +} +.post-content, +post-custom { + box-sizing: border-box; + padding-left: 10%; + padding-right: 10%; +} +@media (max-width: 767px) { + .post-content, + post-custom { + padding-left: 2rem; + padding-right: 2rem; + } +} +@media (max-width: 424px) { + .post-content, + post-custom { + padding-left: 1rem; + padding-right: 1rem; + } + .anchorjs-link-left { + opacity: 0 !important; + } +} +.page-content strong, +.post-content strong { + font-weight: bold; +} +.page-content > *:first-child, +.post-content > *:first-child { + margin-top: 0; +} +.page-content img, +.post-content img { + object-fit: cover; + max-width: 100%; +} +@media (max-width: 767px) { + .page-content, + .post-content { + overflow-x: hidden; + } +} +.post-metas { + display: flex; + flex-wrap: wrap; + font-size: 0.9rem; +} +.post-meta > *:not(.hover-with-bg) { + margin-right: 0.2rem; +} +.post-prevnext { + display: flex; + flex-wrap: wrap; + justify-content: space-between; + font-size: 0.9rem; + margin-left: -0.35rem; + margin-right: -0.35rem; +} +.post-prevnext .post-prev, +.post-prevnext .post-next { + display: flex; + padding-left: 0; + padding-right: 0; +} +.post-prevnext .post-prev i, +.post-prevnext .post-next i { + font-size: 1.5rem; +} +.post-prevnext .post-prev a, +.post-prevnext .post-next a { + display: flex; + align-items: center; +} +.post-prevnext .post-prev .hidden-mobile, +.post-prevnext .post-next .hidden-mobile { + display: -webkit-box; + -webkit-box-orient: vertical; + -webkit-line-clamp: 2; + text-overflow: ellipsis; + overflow: hidden; +} +@media (max-width: 575px) { + .post-prevnext .post-prev .hidden-mobile, + .post-prevnext .post-next .hidden-mobile { + display: none; + } +} +.post-prevnext .post-prev:hover i, +.post-prevnext .post-prev:active i, +.post-prevnext .post-next:hover i, +.post-prevnext .post-next:active i { + -webkit-animation-duration: 1s; + animation-duration: 1s; + -webkit-animation-delay: 0.1s; + animation-delay: 0.1s; + -webkit-animation-timing-function: ease-in-out; + animation-timing-function: ease-in-out; + -webkit-animation-iteration-count: infinite; + animation-iteration-count: infinite; + -webkit-animation-fill-mode: forwards; + animation-fill-mode: forwards; + -webkit-animation-direction: alternate; + animation-direction: alternate; +} +.post-prevnext .post-prev:hover i, +.post-prevnext .post-prev:active i { + -webkit-animation-name: post-prev-anim; + animation-name: post-prev-anim; +} +.post-prevnext .post-next:hover i, +.post-prevnext .post-next:active i { + -webkit-animation-name: post-next-anim; + animation-name: post-next-anim; +} +.post-prevnext .post-next { + justify-content: flex-end; +} +.post-prevnext .fa-chevron-left { + margin-right: 0.5rem; +} +.post-prevnext .fa-chevron-right { + margin-left: 0.5rem; +} +.custom, +#comments { + margin-top: 2rem; +} +#comments noscript { + display: block; + text-align: center; + padding: 2rem 0; +} +.visitors { + font-size: 0.8em; + padding: 0.45rem; + float: right; +} +a.fancybox:hover { + text-decoration: none; +} +mjx-container, +.mjx-container { + overflow-x: auto; + overflow-y: hidden !important; + padding: 0.5em 0; +} +mjx-container:focus, +.mjx-container:focus, +mjx-container svg:focus, +.mjx-container svg:focus { + outline: none; +} +.mjx-char { + line-height: 1; +} +.katex-block { + overflow-x: auto; +} +.katex, +.mjx-mrow { + white-space: pre-wrap !important; +} +.footnote-ref [class*=hint--][aria-label]:after { + max-width: 12rem; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; +} +@-moz-keyframes post-prev-anim { + 0% { + -webkit-transform: translateX(0); + transform: translateX(0); + } + 50% { + -webkit-transform: translateX(-0.35rem); + transform: translateX(-0.35rem); + } + 100% { + -webkit-transform: translateX(0); + transform: translateX(0); + } +} +@-webkit-keyframes post-prev-anim { + 0% { + -webkit-transform: translateX(0); + transform: translateX(0); + } + 50% { + -webkit-transform: translateX(-0.35rem); + transform: translateX(-0.35rem); + } + 100% { + -webkit-transform: translateX(0); + transform: translateX(0); + } +} +@-o-keyframes post-prev-anim { + 0% { + -webkit-transform: translateX(0); + transform: translateX(0); + } + 50% { + -webkit-transform: translateX(-0.35rem); + transform: translateX(-0.35rem); + } + 100% { + -webkit-transform: translateX(0); + transform: translateX(0); + } +} +@keyframes post-prev-anim { + 0% { + -webkit-transform: translateX(0); + transform: translateX(0); + } + 50% { + -webkit-transform: translateX(-0.35rem); + transform: translateX(-0.35rem); + } + 100% { + -webkit-transform: translateX(0); + transform: translateX(0); + } +} +@-moz-keyframes post-next-anim { + 0% { + -webkit-transform: translateX(0); + transform: translateX(0); + } + 50% { + -webkit-transform: translateX(0.35rem); + transform: translateX(0.35rem); + } + 100% { + -webkit-transform: translateX(0); + transform: translateX(0); + } +} +@-webkit-keyframes post-next-anim { + 0% { + -webkit-transform: translateX(0); + transform: translateX(0); + } + 50% { + -webkit-transform: translateX(0.35rem); + transform: translateX(0.35rem); + } + 100% { + -webkit-transform: translateX(0); + transform: translateX(0); + } +} +@-o-keyframes post-next-anim { + 0% { + -webkit-transform: translateX(0); + transform: translateX(0); + } + 50% { + -webkit-transform: translateX(0.35rem); + transform: translateX(0.35rem); + } + 100% { + -webkit-transform: translateX(0); + transform: translateX(0); + } +} +@keyframes post-next-anim { + 0% { + -webkit-transform: translateX(0); + transform: translateX(0); + } + 50% { + -webkit-transform: translateX(0.35rem); + transform: translateX(0.35rem); + } + 100% { + -webkit-transform: translateX(0); + transform: translateX(0); + } +} +.note { + padding: 0.75rem; + border-left: 0.35rem solid; + border-radius: 0.25rem; + margin: 1.5rem 0; + color: var(--text-color); + transition: color 0.2s ease-in-out; + font-size: 0.9rem; +} +.note a { + color: var(--text-color); + transition: color 0.2s ease-in-out; +} +.note *:last-child { + margin-bottom: 0; +} +.note-primary { + background-color: rgba(183,160,224,0.25); + border-color: #6f42c1; +} +.note-secondary, +note-default { + background-color: rgba(187,187,187,0.25); + border-color: #777; +} +.note-success { + background-color: rgba(174,220,174,0.25); + border-color: #5cb85c; +} +.note-danger { + background-color: rgba(236,169,167,0.25); + border-color: #d9534f; +} +.note-warning { + background-color: rgba(248,214,166,0.25); + border-color: #f0ad4e; +} +.note-info { + background-color: rgba(160,197,228,0.25); + border-color: #428bca; +} +.note-light { + background-color: rgba(254,254,254,0.25); + border-color: #0f0f0f; +} +.label { + display: inline; + border-radius: 3px; + font-size: 85%; + margin: 0; + padding: 0.2em 0.4em; + color: var(--text-color); + transition: color 0.2s ease-in-out; +} +.label-default { + background: rgba(187,187,187,0.25); +} +.label-primary { + background: rgba(183,160,224,0.25); +} +.label-info { + background: rgba(160,197,228,0.25); +} +.label-success { + background: rgba(174,220,174,0.25); +} +.label-warning { + background: rgba(248,214,166,0.25); +} +.label-danger { + background: rgba(236,169,167,0.25); +} +.markdown-body .btn { + border: 1px solid var(--line-color); + background-color: var(--button-bg-color); + color: var(--text-color); + transition: color 0.2s ease-in-out, background 0.2s ease-in-out, border-color 0.2s ease-in-out; + border-radius: 0.25rem; + display: inline-block; + font-size: 0.875em; + line-height: 2; + padding: 0 0.75rem; + margin-bottom: 1rem; +} +.markdown-body .btn:hover { + background-color: var(--button-hover-bg-color); + text-decoration: none; +} +.group-image-container { + margin: 1.5rem auto; +} +.group-image-container img { + margin: 0 auto; + border-radius: 3px; + background-color: transparent; + box-shadow: 0 3px 9px 0 rgba(0,0,0,0.15), 0 3px 9px 0 rgba(0,0,0,0.15); +} +.group-image-row { + margin-bottom: 0.5rem; + display: flex; + justify-content: center; +} +.group-image-wrap { + flex: 1; + display: flex; + justify-content: center; +} +.group-image-wrap:not(:last-child) { + margin-right: 0.25rem; +} +input[type=checkbox] { + margin: 0 0.2em 0.2em 0; + vertical-align: middle; +} +.list-group a ~ p.h5 { + margin-top: 1rem; +} +.list-group-item { + display: flex; + background-color: transparent; + border: 0; +} +.list-group-item time { + flex: 0 0 5rem; +} +.list-group-item .list-group-item-title { + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; +} +@media (max-width: 575px) { + .list-group-item { + font-size: 0.95rem; + padding: 0.5rem 0.75rem; + } + .list-group-item time { + flex: 0 0 4rem; + } +} +.list-group-item-action { + color: var(--text-color); +} +.list-group-item-action:focus, +.list-group-item-action:hover { + color: var(--link-hover-color); + background-color: var(--link-hover-bg-color); +} +.about-avatar { + position: relative; + margin: -8rem auto 1rem; + width: 10rem; + height: 10rem; + z-index: 3; +} +.about-avatar img { + width: 100%; + height: 100%; + border-radius: 50%; + background-color: transparent; + object-fit: cover; + box-shadow: 0 2px 5px 0 rgba(0,0,0,0.16), 0 2px 10px 0 rgba(0,0,0,0.12); +} +.about-info > div { + margin-bottom: 0.5rem; +} +.about-name { + font-size: 1.75rem; + font-weight: bold; +} +.about-intro { + font-size: 1rem; +} +.about-icons > a:not(:last-child) { + margin-right: 0.5rem; +} +.about-icons > a > i { + font-size: 1.5rem; +} +.category-bar .category-list { + max-height: 85vh; + overflow-y: auto; + overflow-x: hidden; +} +.category-bar .category-list::-webkit-scrollbar { + display: none; +} +.category-bar .category-list > .category-sub > a { + font-weight: bold; + font-size: 1.2rem; +} +.category-bar .category-list .category-item-action i { + margin: 0; +} +.category-bar .category-list .category-subitem.list-group-item { + padding-left: 0.5rem; + padding-right: 0; +} +.category-bar .category-list .category-collapse .category-post-list { + margin-top: 0.25rem; + margin-bottom: 0.5rem; +} +.category-bar .category-list .category-collapse .category-post { + font-size: 0.9rem; + line-height: 1.75; +} +.category-bar .category-list .category-item-action:hover { + background-color: initial; +} +.category-bar .list-group-item { + padding: 0; +} +.category-bar .list-group-item.active { + color: var(--link-hover-color); + background-color: initial; + font-weight: bold; + font-family: "iconfont"; + font-style: normal; + -webkit-font-smoothing: antialiased; +} +.category-bar .list-group-item.active::before { + content: "\e61f"; + font-weight: initial; + margin-right: 0.25rem; +} +.category-bar .list-group-count { + margin-left: 0.2rem; + margin-right: 0.2rem; + font-size: 0.9em; +} +.category-bar .list-group-item-action:focus, +.category-bar .list-group-item-action:hover { + background-color: initial; +} +.category-chains { + display: flex; + flex-wrap: wrap; +} +.category-chains > *:not(:last-child) { + margin-right: 1em; +} +.category:not(:last-child) { + margin-bottom: 1rem; +} +.category .category-item, +.category .category-subitem { + font-weight: bold; + display: flex; + align-items: center; +} +.category .category-item { + font-size: 1.25rem; +} +.category .category-subitem { + font-size: 1.1rem; +} +.category .category-collapse { + padding-left: 1.25rem; + width: 100%; +} +.category .category-count { + font-size: 0.9rem; + font-weight: initial; + min-width: 1.3em; + line-height: 1.3em; + display: flex; + align-items: center; +} +.category .category-count i { + padding-right: 0.25rem; +} +.category .category-count span { + width: 2rem; +} +.category .category-post { + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; +} +.category .category-item-action:not(.collapsed) > i { + transform: rotate(90deg); + transform-origin: center center; +} +.category .category-item-action i { + transition: transform 0.3s ease-out; + display: inline-block; + margin-left: 0.25rem; +} +.category .category-item-action .category:hover { + z-index: 1; + color: var(--link-hover-color); + text-decoration: none; + background-color: var(--link-hover-bg-color); +} +.category .row { + margin-left: 0; + margin-right: 0; +} +.tagcloud { + padding: 1rem 5%; +} +.tagcloud a { + display: inline-block; + padding: 0.5rem; +} +.tagcloud a:hover { + color: var(--link-hover-color) !important; +} +.links .card { + box-shadow: none; + min-width: 33%; + background-color: transparent; + border: 0; +} +.links .card-body { + margin: 1rem 0; + padding: 1rem; + border-radius: 0.3rem; + display: block; + width: 100%; + height: 100%; +} +.links .card-body:hover .link-avatar { + transform: scale(1.1); +} +.links .card-content { + display: flex; + flex-wrap: nowrap; + width: 100%; + height: 3.5rem; +} +.link-avatar { + flex: none; + width: 3rem; + height: 3rem; + margin-right: 0.75rem; + object-fit: cover; + transition-duration: 0.2s; + transition-timing-function: ease-in-out; +} +.link-avatar img { + width: 100%; + height: 100%; + border-radius: 50%; + background-color: transparent; + object-fit: cover; +} +.link-text { + flex: 1; + display: grid; + flex-direction: column; + line-height: 1.5; +} +.link-title { + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + color: var(--text-color); + font-weight: bold; +} +.link-intro { + max-height: 2rem; + font-size: 0.85rem; + line-height: 1.2; + color: var(--sec-text-color); + display: -webkit-box; + -webkit-box-orient: vertical; + -webkit-line-clamp: 2; + text-overflow: ellipsis; + overflow: hidden; +} +@media (max-width: 767px) { + .links { + display: flex; + flex-direction: column; + justify-content: center; + align-items: center; + } + .links .card { + padding-left: 2rem; + padding-right: 2rem; + } +} +@media (min-width: 768px) { + .link-text:only-child { + margin-left: 1rem; + } +} diff --git a/img/1.jpg b/img/1.jpg new file mode 100644 index 0000000..5c645da Binary files /dev/null and b/img/1.jpg differ diff --git a/img/2.jpg b/img/2.jpg new file mode 100644 index 0000000..c267369 Binary files /dev/null and b/img/2.jpg differ diff --git a/img/avatar.png b/img/avatar.png new file mode 100644 index 0000000..ffd1c77 Binary files /dev/null and b/img/avatar.png differ diff --git a/img/bg/home.jpg b/img/bg/home.jpg new file mode 100644 index 0000000..51e5d96 Binary files /dev/null and b/img/bg/home.jpg differ diff --git a/img/default.png b/img/default.png new file mode 100644 index 0000000..2bc2cd7 Binary files /dev/null and b/img/default.png differ diff --git a/img/fluid.png b/img/fluid.png new file mode 100644 index 0000000..368a58a Binary files /dev/null and b/img/fluid.png differ diff --git a/img/loading.gif b/img/loading.gif new file mode 100644 index 0000000..c5126ed Binary files /dev/null and b/img/loading.gif differ diff --git a/img/police_beian.png b/img/police_beian.png new file mode 100644 index 0000000..60190da Binary files /dev/null and b/img/police_beian.png differ diff --git a/index.html b/index.html new file mode 100644 index 0000000..4e109ad --- /dev/null +++ b/index.html @@ -0,0 +1,1021 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + LuckyCrise + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ + + + + + +
+ +
+ +
+ +
+
+ +
+
+
+ + + + + + + + + +
+ + + +
+ + + +
+ + + +
+ +
+ + + +
+ + + +
+ + + +
+ +
+ + + +
+ + + + + + + +
+
+
+
+
+ + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/js/boot.js b/js/boot.js new file mode 100644 index 0000000..26c3a1a --- /dev/null +++ b/js/boot.js @@ -0,0 +1,22 @@ +/* global Fluid */ + +Fluid.boot = {}; + +Fluid.boot.registerEvents = function() { + Fluid.events.billboard(); + Fluid.events.registerNavbarEvent(); + Fluid.events.registerParallaxEvent(); + Fluid.events.registerScrollDownArrowEvent(); + Fluid.events.registerScrollTopArrowEvent(); + Fluid.events.registerImageLoadedEvent(); +}; + +Fluid.boot.refresh = function() { + Fluid.plugins.fancyBox(); + Fluid.plugins.codeWidget(); + Fluid.events.refresh(); +}; + +document.addEventListener('DOMContentLoaded', function() { + Fluid.boot.registerEvents(); +}); diff --git a/js/color-schema.js b/js/color-schema.js new file mode 100644 index 0000000..07772e0 --- /dev/null +++ b/js/color-schema.js @@ -0,0 +1,275 @@ +/* global Fluid */ + +/** + * Modified from https://blog.skk.moe/post/hello-darkmode-my-old-friend/ + */ +(function(window, document) { + var rootElement = document.documentElement; + var colorSchemaStorageKey = 'Fluid_Color_Scheme'; + var colorSchemaMediaQueryKey = '--color-mode'; + var userColorSchemaAttributeName = 'data-user-color-scheme'; + var defaultColorSchemaAttributeName = 'data-default-color-scheme'; + var colorToggleButtonSelector = '#color-toggle-btn'; + var colorToggleIconSelector = '#color-toggle-icon'; + + function setLS(k, v) { + try { + localStorage.setItem(k, v); + } catch (e) {} + } + + function removeLS(k) { + try { + localStorage.removeItem(k); + } catch (e) {} + } + + function getLS(k) { + try { + return localStorage.getItem(k); + } catch (e) { + return null; + } + } + + function getSchemaFromHTML() { + var res = rootElement.getAttribute(defaultColorSchemaAttributeName); + if (typeof res === 'string') { + return res.replace(/["'\s]/g, ''); + } + return null; + } + + function getSchemaFromCSSMediaQuery() { + var res = getComputedStyle(rootElement).getPropertyValue( + colorSchemaMediaQueryKey + ); + if (typeof res === 'string') { + return res.replace(/["'\s]/g, ''); + } + return null; + } + + function resetSchemaAttributeAndLS() { + rootElement.setAttribute(userColorSchemaAttributeName, getDefaultColorSchema()); + removeLS(colorSchemaStorageKey); + } + + var validColorSchemaKeys = { + dark : true, + light: true + }; + + function getDefaultColorSchema() { + // 取默认字段的值 + var schema = getSchemaFromHTML(); + // 如果明确指定了 schema 则返回 + if (validColorSchemaKeys[schema]) { + return schema; + } + // 默认优先按 prefers-color-scheme + schema = getSchemaFromCSSMediaQuery(); + if (validColorSchemaKeys[schema]) { + return schema; + } + // 否则按本地时间是否大于 18 点或凌晨 0 ~ 6 点 + var hours = new Date().getHours(); + if (hours >= 18 || (hours >= 0 && hours <= 6)) { + return 'dark'; + } + return 'light'; + } + + function applyCustomColorSchemaSettings(schema) { + // 接受从「开关」处传来的模式,或者从 localStorage 读取,否则按默认设置值 + var current = schema || getLS(colorSchemaStorageKey) || getDefaultColorSchema(); + + if (current === getDefaultColorSchema()) { + // 当用户切换的显示模式和默认模式相同时,则恢复为自动模式 + resetSchemaAttributeAndLS(); + } else if (validColorSchemaKeys[current]) { + rootElement.setAttribute( + userColorSchemaAttributeName, + current + ); + } else { + // 特殊情况重置 + resetSchemaAttributeAndLS(); + return; + } + + // 根据当前模式设置图标 + setButtonIcon(current); + + // 设置代码高亮 + setHighlightCSS(current); + + // 设置其他应用 + setApplications(current); + } + + var invertColorSchemaObj = { + dark : 'light', + light: 'dark' + }; + + function getIconClass(scheme) { + return 'icon-' + scheme; + } + + function toggleCustomColorSchema() { + var currentSetting = getLS(colorSchemaStorageKey); + + if (validColorSchemaKeys[currentSetting]) { + // 从 localStorage 中读取模式,并取相反的模式 + currentSetting = invertColorSchemaObj[currentSetting]; + } else if (currentSetting === null) { + // 当 localStorage 中没有相关值,或者 localStorage 抛了 Error + // 先按照按钮的状态进行切换 + var iconElement = document.querySelector(colorToggleIconSelector); + if (iconElement) { + currentSetting = iconElement.getAttribute('data'); + } + if (!iconElement || !validColorSchemaKeys[currentSetting]) { + // 当 localStorage 中没有相关值,或者 localStorage 抛了 Error,则读取默认值并切换到相反的模式 + currentSetting = invertColorSchemaObj[getSchemaFromCSSMediaQuery()]; + } + } else { + return; + } + // 将相反的模式写入 localStorage + setLS(colorSchemaStorageKey, currentSetting); + + return currentSetting; + } + + function setButtonIcon(schema) { + if (validColorSchemaKeys[schema]) { + // 切换图标 + var icon = getIconClass('dark'); + if (schema) { + icon = getIconClass(schema); + } + var iconElement = document.querySelector(colorToggleIconSelector); + if (iconElement) { + iconElement.setAttribute( + 'class', + 'iconfont ' + icon + ); + iconElement.setAttribute( + 'data', + invertColorSchemaObj[schema] + ); + } else { + // 如果图标不存在则说明图标还没加载出来,等到页面全部加载再尝试切换 + Fluid.utils.waitElementLoaded(colorToggleIconSelector, function() { + var iconElement = document.querySelector(colorToggleIconSelector); + if (iconElement) { + iconElement.setAttribute( + 'class', + 'iconfont ' + icon + ); + iconElement.setAttribute( + 'data', + invertColorSchemaObj[schema] + ); + } + }); + } + } + } + + function setHighlightCSS(schema) { + // 启用对应的代码高亮的样式 + var lightCss = document.getElementById('highlight-css'); + var darkCss = document.getElementById('highlight-css-dark'); + if (schema === 'dark') { + if (darkCss) { + darkCss.removeAttribute('disabled'); + } + if (lightCss) { + lightCss.setAttribute('disabled', ''); + } + } else { + if (lightCss) { + lightCss.removeAttribute('disabled'); + } + if (darkCss) { + darkCss.setAttribute('disabled', ''); + } + } + + setTimeout(function() { + // 设置代码块组件样式 + document.querySelectorAll('.markdown-body pre').forEach((pre) => { + var cls = Fluid.utils.getBackgroundLightness(pre) >= 0 ? 'code-widget-light' : 'code-widget-dark'; + var widget = pre.querySelector('.code-widget-light, .code-widget-dark'); + if (widget) { + widget.classList.remove('code-widget-light', 'code-widget-dark'); + widget.classList.add(cls); + } + }); + }, 200); + } + + function setApplications(schema) { + // 设置 remark42 评论主题 + if (window.REMARK42) { + window.REMARK42.changeTheme(schema); + } + + // 设置 cusdis 评论主题 + if (window.CUSDIS) { + window.CUSDIS.setTheme(schema); + } + + // 设置 utterances 评论主题 + var utterances = document.querySelector('.utterances-frame'); + if (utterances) { + var utterancesTheme = schema === 'dark' ? window.UtterancesThemeDark : window.UtterancesThemeLight; + const message = { + type : 'set-theme', + theme: utterancesTheme + }; + utterances.contentWindow.postMessage(message, 'https://utteranc.es'); + } + + // 设置 giscus 评论主题 + var giscus = document.querySelector('iframe.giscus-frame'); + if (giscus) { + var giscusTheme = schema === 'dark' ? window.GiscusThemeDark : window.GiscusThemeLight; + const message = { + setConfig: { + theme: giscusTheme, + } + }; + giscus.contentWindow.postMessage({ 'giscus': message }, 'https://giscus.app'); + } + } + + // 当页面加载时,将显示模式设置为 localStorage 中自定义的值(如果有的话) + applyCustomColorSchemaSettings(); + + Fluid.utils.waitElementLoaded(colorToggleIconSelector, function() { + applyCustomColorSchemaSettings(); + var button = document.querySelector(colorToggleButtonSelector); + if (button) { + // 当用户点击切换按钮时,获得新的显示模式、写入 localStorage、并在页面上生效 + button.addEventListener('click', function() { + applyCustomColorSchemaSettings(toggleCustomColorSchema()); + }); + var icon = document.querySelector(colorToggleIconSelector); + if (icon) { + // 光标悬停在按钮上时,切换图标 + button.addEventListener('mouseenter', function() { + var current = icon.getAttribute('data'); + icon.classList.replace(getIconClass(invertColorSchemaObj[current]), getIconClass(current)); + }); + button.addEventListener('mouseleave', function() { + var current = icon.getAttribute('data'); + icon.classList.replace(getIconClass(current), getIconClass(invertColorSchemaObj[current])); + }); + } + } + }); +})(window, document); diff --git a/js/events.js b/js/events.js new file mode 100644 index 0000000..149eadc --- /dev/null +++ b/js/events.js @@ -0,0 +1,184 @@ +/* global Fluid */ + +HTMLElement.prototype.wrap = function(wrapper) { + this.parentNode.insertBefore(wrapper, this); + this.parentNode.removeChild(this); + wrapper.appendChild(this); +}; + +Fluid.events = { + + registerNavbarEvent: function() { + var navbar = jQuery('#navbar'); + if (navbar.length === 0) { + return; + } + var submenu = jQuery('#navbar .dropdown-menu'); + if (navbar.offset().top > 0) { + navbar.removeClass('navbar-dark'); + submenu.removeClass('navbar-dark'); + } + Fluid.utils.listenScroll(function() { + navbar[navbar.offset().top > 50 ? 'addClass' : 'removeClass']('top-nav-collapse'); + submenu[navbar.offset().top > 50 ? 'addClass' : 'removeClass']('dropdown-collapse'); + if (navbar.offset().top > 0) { + navbar.removeClass('navbar-dark'); + submenu.removeClass('navbar-dark'); + } else { + navbar.addClass('navbar-dark'); + submenu.removeClass('navbar-dark'); + } + }); + jQuery('#navbar-toggler-btn').on('click', function() { + jQuery('.animated-icon').toggleClass('open'); + jQuery('#navbar').toggleClass('navbar-col-show'); + }); + }, + + registerParallaxEvent: function() { + var ph = jQuery('#banner[parallax="true"]'); + if (ph.length === 0) { + return; + } + var board = jQuery('#board'); + if (board.length === 0) { + return; + } + var parallax = function() { + var pxv = jQuery(window).scrollTop() / 5; + var offset = parseInt(board.css('margin-top'), 10); + var max = 96 + offset; + if (pxv > max) { + pxv = max; + } + ph.css({ + transform: 'translate3d(0,' + pxv + 'px,0)' + }); + var sideCol = jQuery('.side-col'); + if (sideCol) { + sideCol.css({ + 'padding-top': pxv + 'px' + }); + } + }; + Fluid.utils.listenScroll(parallax); + }, + + registerScrollDownArrowEvent: function() { + var scrollbar = jQuery('.scroll-down-bar'); + if (scrollbar.length === 0) { + return; + } + scrollbar.on('click', function() { + Fluid.utils.scrollToElement('#board', -jQuery('#navbar').height()); + }); + }, + + registerScrollTopArrowEvent: function() { + var topArrow = jQuery('#scroll-top-button'); + if (topArrow.length === 0) { + return; + } + var board = jQuery('#board'); + if (board.length === 0) { + return; + } + var posDisplay = false; + var scrollDisplay = false; + // Position + var setTopArrowPos = function() { + var boardRight = board[0].getClientRects()[0].right; + var bodyWidth = document.body.offsetWidth; + var right = bodyWidth - boardRight; + posDisplay = right >= 50; + topArrow.css({ + 'bottom': posDisplay && scrollDisplay ? '20px' : '-60px', + 'right' : right - 64 + 'px' + }); + }; + setTopArrowPos(); + jQuery(window).resize(setTopArrowPos); + // Display + var headerHeight = board.offset().top; + Fluid.utils.listenScroll(function() { + var scrollHeight = document.body.scrollTop + document.documentElement.scrollTop; + scrollDisplay = scrollHeight >= headerHeight; + topArrow.css({ + 'bottom': posDisplay && scrollDisplay ? '20px' : '-60px' + }); + }); + // Click + topArrow.on('click', function() { + jQuery('body,html').animate({ + scrollTop: 0, + easing : 'swing' + }); + }); + }, + + registerImageLoadedEvent: function() { + if (!('NProgress' in window)) { return; } + + var bg = document.getElementById('banner'); + if (bg) { + var src = bg.style.backgroundImage; + var url = src.match(/\((.*?)\)/)[1].replace(/(['"])/g, ''); + var img = new Image(); + img.onload = function() { + window.NProgress && window.NProgress.inc(0.2); + }; + img.src = url; + if (img.complete) { img.onload(); } + } + + var notLazyImages = jQuery('main img:not([lazyload])'); + var total = notLazyImages.length; + for (const img of notLazyImages) { + const old = img.onload; + img.onload = function() { + old && old(); + window.NProgress && window.NProgress.inc(0.5 / total); + }; + if (img.complete) { img.onload(); } + } + }, + + registerRefreshCallback: function(callback) { + if (!Array.isArray(Fluid.events._refreshCallbacks)) { + Fluid.events._refreshCallbacks = []; + } + Fluid.events._refreshCallbacks.push(callback); + }, + + refresh: function() { + if (Array.isArray(Fluid.events._refreshCallbacks)) { + for (var callback of Fluid.events._refreshCallbacks) { + if (callback instanceof Function) { + callback(); + } + } + } + }, + + billboard: function() { + if (!('console' in window)) { + return; + } + // eslint-disable-next-line no-console + console.log(` +------------------------------------------------ +| | +| ________ __ _ __ | +| |_ __ |[ | (_) | ] | +| | |_ \\_| | | __ _ __ .--.| | | +| | _| | |[ | | | [ |/ /'\`\\' | | +| _| |_ | | | \\_/ |, | || \\__/ | | +| |_____| [___]'.__.'_/[___]'.__.;__] | +| | +| Powered by Hexo x Fluid | +| GitHub: https://git.io/JqpVD | +| | +------------------------------------------------ + `); + } +}; diff --git a/js/img-lazyload.js b/js/img-lazyload.js new file mode 100644 index 0000000..c0c8e4e --- /dev/null +++ b/js/img-lazyload.js @@ -0,0 +1,10 @@ +/* global Fluid, CONFIG */ + +(function(window, document) { + for (const each of document.querySelectorAll('img[lazyload]')) { + Fluid.utils.waitElementVisible(each, function() { + each.removeAttribute('srcset'); + each.removeAttribute('lazyload'); + }, CONFIG.lazyload.offset_factor); + } +})(window, document); diff --git a/js/leancloud.js b/js/leancloud.js new file mode 100644 index 0000000..ab901ce --- /dev/null +++ b/js/leancloud.js @@ -0,0 +1,192 @@ +/* global CONFIG */ +// eslint-disable-next-line no-console + +(function(window, document) { + // 查询存储的记录 + function getRecord(Counter, target) { + return new Promise(function(resolve, reject) { + Counter('get', '/classes/Counter?where=' + encodeURIComponent(JSON.stringify({ target }))) + .then(resp => resp.json()) + .then(({ results, code, error }) => { + if (code === 401) { + throw error; + } + if (results && results.length > 0) { + var record = results[0]; + resolve(record); + } else { + Counter('post', '/classes/Counter', { target, time: 0 }) + .then(resp => resp.json()) + .then((record, error) => { + if (error) { + throw error; + } + resolve(record); + }).catch(error => { + console.error('Failed to create: ', error); + reject(error); + }); + } + }).catch((error) => { + console.error('LeanCloud Counter Error: ', error); + reject(error); + }); + }); + } + + // 发起自增请求 + function increment(Counter, incrArr) { + return new Promise(function(resolve, reject) { + Counter('post', '/batch', { + 'requests': incrArr + }).then((res) => { + res = res.json(); + if (res.error) { + throw res.error; + } + resolve(res); + }).catch((error) => { + console.error('Failed to save visitor count: ', error); + reject(error); + }); + }); + } + + // 构建自增请求体 + function buildIncrement(objectId) { + return { + 'method': 'PUT', + 'path' : `/1.1/classes/Counter/${objectId}`, + 'body' : { + 'time': { + '__op' : 'Increment', + 'amount': 1 + } + } + }; + } + + // 校验是否为有效的 Host + function validHost() { + if (CONFIG.web_analytics.leancloud.ignore_local) { + var hostname = window.location.hostname; + if (hostname === 'localhost' || hostname === '127.0.0.1') { + return false; + } + } + return true; + } + + // 校验是否为有效的 UV + function validUV() { + var key = 'LeanCloud_UV_Flag'; + var flag = localStorage.getItem(key); + if (flag) { + // 距离标记小于 24 小时则不计为 UV + if (new Date().getTime() - parseInt(flag, 10) <= 86400000) { + return false; + } + } + localStorage.setItem(key, new Date().getTime().toString()); + return true; + } + + function addCount(Counter) { + var enableIncr = CONFIG.web_analytics.enable && !Fluid.ctx.dnt && validHost(); + var getterArr = []; + var incrArr = []; + + // 请求 PV 并自增 + var pvCtn = document.querySelector('#leancloud-site-pv-container'); + if (pvCtn) { + var pvGetter = getRecord(Counter, 'site-pv').then((record) => { + enableIncr && incrArr.push(buildIncrement(record.objectId)); + var ele = document.querySelector('#leancloud-site-pv'); + if (ele) { + ele.innerText = (record.time || 0) + (enableIncr ? 1 : 0); + pvCtn.style.display = 'inline'; + } + }); + getterArr.push(pvGetter); + } + + // 请求 UV 并自增 + var uvCtn = document.querySelector('#leancloud-site-uv-container'); + if (uvCtn) { + var uvGetter = getRecord(Counter, 'site-uv').then((record) => { + var incrUV = validUV() && enableIncr; + incrUV && incrArr.push(buildIncrement(record.objectId)); + var ele = document.querySelector('#leancloud-site-uv'); + if (ele) { + ele.innerText = (record.time || 0) + (incrUV ? 1 : 0); + uvCtn.style.display = 'inline'; + } + }); + getterArr.push(uvGetter); + } + + // 如果有页面浏览数节点,则请求浏览数并自增 + var viewCtn = document.querySelector('#leancloud-page-views-container'); + if (viewCtn) { + var path = eval(CONFIG.web_analytics.leancloud.path || 'window.location.pathname'); + var target = decodeURI(path.replace(/\/*(index.html)?$/, '/')); + var viewGetter = getRecord(Counter, target).then((record) => { + enableIncr && incrArr.push(buildIncrement(record.objectId)); + var ele = document.querySelector('#leancloud-page-views'); + if (ele) { + ele.innerText = (record.time || 0) + (enableIncr ? 1 : 0); + viewCtn.style.display = 'inline'; + } + }); + getterArr.push(viewGetter); + } + + // 如果启动计数自增,批量发起自增请求 + if (enableIncr) { + Promise.all(getterArr).then(() => { + incrArr.length > 0 && increment(Counter, incrArr); + }); + } + } + + var appId = CONFIG.web_analytics.leancloud.app_id; + var appKey = CONFIG.web_analytics.leancloud.app_key; + var serverUrl = CONFIG.web_analytics.leancloud.server_url; + + if (!appId) { + throw new Error('LeanCloud appId is empty'); + } + if (!appKey) { + throw new Error('LeanCloud appKey is empty'); + } + + function fetchData(api_server) { + var Counter = (method, url, data) => { + return fetch(`${api_server}/1.1${url}`, { + method, + headers: { + 'X-LC-Id' : appId, + 'X-LC-Key' : appKey, + 'Content-Type': 'application/json' + }, + body: JSON.stringify(data) + }); + }; + + addCount(Counter); + } + + var apiServer = serverUrl || `https://${appId.slice(0, 8).toLowerCase()}.api.lncldglobal.com`; + + if (apiServer) { + fetchData(apiServer); + } else { + fetch('https://app-router.leancloud.cn/2/route?appId=' + appId) + .then(resp => resp.json()) + .then((data) => { + if (data.api_server) { + fetchData('https://' + data.api_server); + } + }); + } +})(window, document); diff --git a/js/local-search.js b/js/local-search.js new file mode 100644 index 0000000..95baf52 --- /dev/null +++ b/js/local-search.js @@ -0,0 +1,160 @@ +/* global CONFIG */ + +(function() { + // Modified from [hexo-generator-search](https://github.com/wzpan/hexo-generator-search) + function localSearchFunc(path, searchSelector, resultSelector) { + 'use strict'; + // 0x00. environment initialization + 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'); + } + + if ($result.attr('class').indexOf('list-group-item') === -1) { + $result.html('
Loading...

Loading...
'); + } + + jQuery.ajax({ + // 0x01. load xml file + url : path, + dataType: 'xml', + success : function(xmlResponse) { + // 0x02. parse xml file + var dataList = jQuery('entry', xmlResponse).map(function() { + return { + title : jQuery('title', this).text(), + content: jQuery('content', this).text(), + url : jQuery('url', this).text() + }; + }).get(); + + if ($result.html().indexOf('list-group-item') === -1) { + $result.html(''); + } + + $input.on('input', function() { + // 0x03. parse query to keywords list + var content = $input.val(); + var resultHTML = ''; + var keywords = content.trim().toLowerCase().split(/[\s-]+/); + $result.html(''); + if (content.trim().length <= 0) { + return $input.removeClass('invalid').removeClass('valid'); + } + // 0x04. perform local searching + dataList.forEach(function(data) { + var isMatch = true; + if (!data.title || data.title.trim() === '') { + data.title = 'Untitled'; + } + var orig_data_title = data.title.trim(); + var data_title = orig_data_title.toLowerCase(); + var orig_data_content = data.content.trim().replace(/<[^>]+>/g, ''); + var data_content = orig_data_content.toLowerCase(); + var data_url = data.url; + var index_title = -1; + var index_content = -1; + var first_occur = -1; + // only match articles with not empty contents + if (data_content !== '') { + keywords.forEach(function(keyword, i) { + index_title = data_title.indexOf(keyword); + index_content = data_content.indexOf(keyword); + + if (index_title < 0 && index_content < 0) { + isMatch = false; + } else { + if (index_content < 0) { + index_content = 0; + } + if (i === 0) { + first_occur = index_content; + } + //content_index.push({index_content:index_content, keyword_len:keyword_len}); + } + }); + } else { + isMatch = false; + } + // 0x05. show search results + if (isMatch) { + resultHTML += '' + orig_data_title + ''; + var content = orig_data_content; + if (first_occur >= 0) { + // cut out 100 characters + var start = first_occur - 20; + var end = first_occur + 80; + + if (start < 0) { + start = 0; + } + + if (start === 0) { + end = 100; + } + + if (end > content.length) { + end = content.length; + } + + var match_content = content.substring(start, end); + + // highlight all keywords + keywords.forEach(function(keyword) { + var regS = new RegExp(keyword, 'gi'); + match_content = match_content.replace(regS, '' + keyword + ''); + }); + + resultHTML += '

' + 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 += '
'; + copyTmpl += 'LANG'; + 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 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 友链 - LuckyCrise + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ + + + + + +
+ +
+ +
+ + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/local-search.xml b/local-search.xml new file mode 100644 index 0000000..2a728fd --- /dev/null +++ b/local-search.xml @@ -0,0 +1,722 @@ + + + + + + + 如何使用 hexo 新建文章 + + /blog/2024/09/04/hello-world/ + + 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.

Quick Start

Create a new post

1
$ hexo new "My New Post"

More info: Writing

Run server

1
$ hexo server

More info: Server

Generate static files

1
$ hexo generate

More info: Generating

Deploy to remote sites

1
$ hexo deploy

More info: Deployment

]]>
+ + + +
+ + + + + [GO] golang中优雅设置参数默认值 + + /blog/2023/04/13/GO-golang%E4%B8%AD%E4%BC%98%E9%9B%85%E8%AE%BE%E7%BD%AE%E5%8F%82%E6%95%B0%E9%BB%98%E8%AE%A4%E5%80%BC/ + + 前言

今天在使用 golang 重构 python 站点时,遇到了一个有趣的事情。就是在 python 函数中参数是可以设置默认值的,这样在函数调用时,就不需要每个参数都传一个值,其实这也是变相的实现重载功能。但是我发现在 golang 中参数是不能设置默认值的,但是基于程序员的直觉,相信此事没那么简单,于是抱着打破沙锅问到底的态度,就有了这篇文章。

不设置默认值带来的不便

首先,通过一个例子,说明我在编码过程中遇到的问题。对于平台后端开发工程师来说,会经常遇到以下场景:
通过

  • 通过多种条件查询数据库记录,比如:select * from user where user_name in (xxx, xxx, xx) and user_region = “shanghai” order by id desc;
  • 需要在不同功能模块做以上方式查询。

基于此,我将这些查询方式抽象成一个方法,之后所有的功能模块,都可以使用该方法进行多条件联合查询数据记录,具体抽象如下:

1
2
3
func DBQueryAllWithConditions(ctx context.Context, orderBy map[string]string, eqFilters map[string]interface{}, inFilters map[string]interface{}, likeFilters map[string]string) {

}

研读开源代码的优雅实现

改进自己的代码

总结

]]>
+ + + + + GO + + + + + + + golang + + + +
+ + + + + [Kubernetes] Kubernetes 核心组件之 kube-apiserver + + /blog/2021/11/15/Kubernetes-Kubernetes-%E6%A0%B8%E5%BF%83%E7%BB%84%E4%BB%B6%E4%B9%8B-kube-apiserver/ + + kube-apiserverKubernetes 最重要的核心组件之一,主要能提供的功能如下:

  • 给集群其他组件提供数据交互以及通信枢纽功能,以RESTful API 的形式提供其他组件查询,修改集群状态的 CURD(Create,Read,Update,Detele)接口,然后将状态储存到 etcd 中;
  • 为用户请求接入认证,授权以及准入控制等功能;
  • 并且可以用来处理乐观锁, 当有并发更新的情况, 对对象做更改就不会被其他客户端覆盖。

如何部署

工作原理

kube-apiserver 提供了 KubernetesREST API,实现了认证、授权、准入控制等安全校验功能,同时也负责集群状态的存储操作(通过 etcd)。

认证

授权

准入控制

API 访问示例

kube-apiserver 提供了为每种语言提供了 SDK,方便用户访问集群其他组件,以及将数据存储或更新到etcd中,如下:

kubectl 访问

  • 查询 kube-apiserver 支持API的版本

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    $ kubectl api-versions
    admissionregistration.k8s.io/v1
    admissionregistration.k8s.io/v1beta1
    apiextensions.k8s.io/v1
    apiextensions.k8s.io/v1beta1
    apps/v1

    ...

    scheduling.k8s.io/v1
    scheduling.k8s.io/v1beta1
    storage.k8s.io/v1
    storage.k8s.io/v1beta1
    traefik.containo.us/v1alpha1
    v1
    xgboostjob.kubeflow.org/v1

  • 查询 kube-apiserver 支持API的资源对象

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    $ kubectl api-resources
    NAME SHORTNAMES APIGROUP NAMESPACED KIND
    bindings true Binding
    componentstatuses cs false ComponentStatus
    configmaps cm true ConfigMap

    ...

    tlsoptions traefik.containo.us true TLSOption
    tlsstores traefik.containo.us true TLSStore
    traefikservices traefik.containo.us true TraefikService
    xgboostjobs xgboostjob.kubeflow.org true XGBoostJob

  • 查看 kube-apiserverv1/namepsace 信息

    1
    2
    3
    $ kubectl get --raw /api/v1/namespaces
    {"kind":"NamespaceList","apiVersion":"v1","metadata":{"selfLink":"/api/v1/namespaces","resourceVersion":"190115288"},"items":[{"metadata":{"name":"airflow","selfLink":"/api/v1/namespaces/airflow","uid":"f4756c7a-8bd7-4988-a69c-c849a3c035be","resourceVersion":"79499605","creationTimestamp":"2021-05-06T07:39:19Z","managedFields":[{"manager":"kubectl-create","operation":"Update","apiVersion":"v1","time":"2021-05-06T07:39:19Z","fieldsType":"FieldsV1","fieldsV1":{"f:status":{"f:phase":{}}}}]},"spec":{"finalizers":["kubernetes"]},"status":{"phase":"Active"}},{"metadata":{"name":"crise","selfLink":"/api/v1/namespaces/crise","uid":"6f943c7a-8419-4c95-bf5a-2972f3631aab","resourceVersion":"155793497","creationTimestamp":"2021-09-26T05:09:22Z","managedFields":[{"manager":"kubectl-create","operation":"Update","apiVersion":"v1","time":"2021-09-26T05:09:22Z","fieldsType":"FieldsV1","fieldsV1":{"f:status":{"f:phase":{}}}}]},"spec":{"finalizers":["kubernetes"]},"status":{"phase":"Active"}},{"metadata":{"name":"default","selfLink":"/api/v1/namespaces/default","uid":"545db544-c735-4d06-a600-981144f245a8","resourceVersion":"157","creationTimestamp":"2020-11-12T07:25:33Z","managedFields":[{"manager":"kube-apiserver","operation":"Update","apiVersion":"v1","time":"2020-11-12T07:25:33Z","fieldsType":"FieldsV1","fieldsV1":{"f:status":{"f:phase":{}}}}]},"spec":{"finalizers":["kubernetes"]},"status":{"phase":"Active"}},{"metadata":{"name":"elastic","selfLink":"/api/v1/namespaces/elastic","uid":"adcddefd-2a71-4b65-af74-ec4d5ac854b4","resourceVersion":"132059434","creationTimestamp":"2021-08-10T08:36:48Z","labels":{"name":"elastic"},"managedFields":[{"manager":"Go-http-client","operation":"Update","apiVersion":"v1","time":"2021-08-10T08:36:48Z","fieldsType":"FieldsV1","fieldsV1":{"f:metadata":{"f:labels":{".":{},"f:name":{}}},"f:status":{"f:phase":{}}}}]},"spec":{"finalizers":["kubernetes"]},"status":{"phase":"Active"}},{"metadata":{"name":"kafka","selfLink":"/api/v1/namespaces/kafka","uid":"82f78a4a-b135-49af-a6d2-34b162deff34","resourceVersion":"126083706","creationTimestamp":"2021-07-30T06:28:47Z","labels":{"name":"kafka"},"managedFields":[{"manager":"Go-http-client","operation":"Update","apiVersion":"v1","time":"2021-07-30T06:28:47Z","fieldsType":"FieldsV1","fieldsV1":{"f:metadata":{"f:labels":{".":{},"f:name":{}}},"f:status":{"f:phase":{}}}}]},"spec":{"finalizers":["kubernetes"]},"status":{"phase":"Active"}},{"metadata":{"name":"kube-node-lease","selfLink":"/api/v1/namespaces/kube-node-lease","uid":"16073100-6a4c-4275-9cb4-914d16e92dd9","resourceVersion":"43","creationTimestamp":"2020-11-12T07:25:32Z","managedFields":[{"manager":"kube-apiserver","operation":"Update","apiVersion":"v1","time":"2020-11-12T07:25:32Z","fieldsType":"FieldsV1","fieldsV1":{"f:status":{"f:phase":{}}}}]},"spec":{"finalizers":["kubernetes"]},"status":{"phase":"Active"}},{"metadata":{"name":"kube-public","selfLink":"/api/v1/namespaces/kube-public","uid":"f6077460-b5ab-4250-ad00-bd7a32745873","resourceVersion":"41","creationTimestamp":"2020-11-12T07:25:32Z","managedFields":[{"manager":"kube-apiserver","operation":"Update","apiVersion":"v1","time":"2020-11-12T07:25:32Z","fieldsType":"FieldsV1","fieldsV1":{"f:status":{"f:phase":{}}}}]},"spec":{"finalizers":["kubernetes"]},"status":{"phase":"Active"}},{"metadata":{"name":"kube-system","selfLink":"/api/v1/namespaces/kube-system","uid":"4671dc1b-9f93-4c23-be43-65579ff03293","resourceVersion":"1051","creationTimestamp":"2020-11-12T07:25:32Z","annotations":{"kubectl.kubernetes.io/last-applied-configuration":"{\"apiVersion\":\"v1\",\"kind\":\"Namespace\",\"metadata\":{\"annotations\":{},\"name\":\"kube-system\"}}\n"},"managedFields":[{"manager":"kube-apiserver","operation":"Update","apiVersion":"v1","time":"2020-11-12T07:25:32Z","fieldsType":"FieldsV1","fieldsV1":{"f:status":{"f:phase":{}}}},{"manager":"kubectl-client-side-apply","operation":"Update","apiVersion":"v1","time":"2020-11-12T07:29:44Z","fieldsType":"FieldsV1","fieldsV1":{"f:metadata":{"f:annotations":{".":{},"f:kubectl.kubernetes.io/last-applied-configuration":{}}}}}]},"spec":{"finalizers":["kubernetes"]},"status":{"phase":"Active"}},{"metadata":{"name":"kubeflow-operators","selfLink":"/api/v1/namespaces/kubeflow-operators","uid":"7a506123-310a-48b7-8c4c-ea95238ed559","resourceVersion":"31999589","creationTimestamp":"2021-01-28T09:08:10Z","managedFields":[{"manager":"kubectl-create","operation":"Update","apiVersion":"v1","time":"2021-01-28T09:08:10Z","fieldsType":"FieldsV1","fieldsV1":{"f:status":{"f:phase":{}}}}]},"spec":{"finalizers":["kubernetes"]},"status":{"phase":"Active"}},{"metadata":{"name":"monitoring","selfLink":"/api/v1/namespaces/monitoring","uid":"28f94d9b-781a-4503-8704-05be7fc0b03f","resourceVersion":"1932","creationTimestamp":"2020-11-12T07:34:49Z","annotations":{"kubectl.kubernetes.io/last-applied-configuration":"{\"apiVersion\":\"v1\",\"kind\":\"Namespace\",\"metadata\":{\"annotations\":{},\"name\":\"monitoring\"}}\n"},"managedFields":[{"manager":"kubectl-client-side-apply","operation":"Update","apiVersion":"v1","time":"2020-11-12T07:34:49Z","fieldsType":"FieldsV1","fieldsV1":{"f:metadata":{"f:annotations":{".":{},"f:kubectl.kubernetes.io/last-applied-configuration":{}}},"f:status":{"f:phase":{}}}}]},"spec":{"finalizers":["kubernetes"]},"status":{"phase":"Active"}},{"metadata":{"name":"portainer","selfLink":"/api/v1/namespaces/portainer","uid":"65ce6ed6-be89-4da5-86da-8a5decf8b190","resourceVersion":"45415995","creationTimestamp":"2021-02-25T08:26:29Z","annotations":{"kubectl.kubernetes.io/last-applied-configuration":"{\"apiVersion\":\"v1\",\"kind\":\"Namespace\",\"metadata\":{\"annotations\":{},\"name\":\"portainer\"}}\n"},"managedFields":[{"manager":"kubectl-client-side-apply","operation":"Update","apiVersion":"v1","time":"2021-02-25T08:26:29Z","fieldsType":"FieldsV1","fieldsV1":{"f:metadata":{"f:annotations":{".":{},"f:kubectl.kubernetes.io/last-applied-configuration":{}}},"f:status":{"f:phase":{}}}}]},"spec":{"finalizers":["kubernetes"]},"status":{"phase":"Active"}},{"metadata":{"name":"rook-ceph","selfLink":"/api/v1/namespaces/rook-ceph","uid":"e4756739-9b75-43ac-8870-60191e336917","resourceVersion":"1716232","creationTimestamp":"2020-11-16T07:37:55Z","managedFields":[{"manager":"kubectl-create","operation":"Update","apiVersion":"v1","time":"2020-11-16T07:37:55Z","fieldsType":"FieldsV1","fieldsV1":{"f:status":{"f:phase":{}}}}]},"spec":{"finalizers":["kubernetes"]},"status":{"phase":"Active"}},{"metadata":{"name":"traefik-system","selfLink":"/api/v1/namespaces/traefik-system","uid":"ed85f7ef-2805-4ba7-84d1-5ae430471202","resourceVersion":"1381","creationTimestamp":"2020-11-12T07:31:22Z","managedFields":[{"manager":"kubectl-create","operation":"Update","apiVersion":"v1","time":"2020-11-12T07:31:22Z","fieldsType":"FieldsV1","fieldsV1":{"f:status":{"f:phase":{}}}}]},"spec":{"finalizers":["kubernetes"]},"status":{"phase":"Active"}}]}

  • 通过启动 proxy 获取集群配置信息

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    $ kubectl proxy --port=8081 & curl http://localhost:8081/api/
    {
    "kind": "APIVersions",
    "versions": [
    "v1"
    ],
    "serverAddressByClientCIDRs": [
    {
    "clientCIDR": "0.0.0.0/0",
    "serverAddress": "10.114.1.100:6443"
    }
    ]
    }
  • 查看集群各组件信息

    1
    2
    3
    4
    5
    6
    $ kubectl cluster-info
    Kubernetes master is running at https://10.114.1.100:6443
    CoreDNS is running at https://10.114.1.100:6443/api/v1/namespaces/kube-system/services/kube-dns:dns/proxy
    kubernetes-dashboard is running at https://10.114.1.100:6443/api/v1/namespaces/kube-system/services/https:kubernetes-dashboard:/proxy
    Metrics-server is running at https://10.114.1.100:6443/api/v1/namespaces/kube-system/services/https:metrics-server:/proxy

curl 访问

  • 在 pod 里面访问

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    $ TOKEN=$(cat /run/secrets/kubernetes.io/serviceaccount/token)
    $ CACERT=/run/secrets/kubernetes.io/serviceaccount/ca.crt
    $ curl --cacert $CACERT --header "Authorization: Bearer $TOKEN" https://$KUBERNETES_SERVICE_HOST:$KUBERNETES_SERVICE_PORT/api
    {
    "kind": "APIVersions",
    "versions": [
    "v1"
    ],
    "serverAddressByClientCIDRs": [
    {
    "clientCIDR": "0.0.0.0/0",
    "serverAddress": "10.114.1.110:6443"(另外一个master节点ip)
    }
    ]
    }
  • 在 master 节点上访问

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    $ APISERVER=$(kubectl config view | grep server | cut -f 2- -d ":" | tr -d " ")
    $ TOKEN=$(kubectl describe secret $(kubectl get secrets | grep default | cut -f1 -d ' ') | grep -E '^token'| cut -f2 -d':'| tr -d '\t')
    $ curl $APISERVER/api --header "Authorization: Bearer $TOKEN" --insecure
    {
    "kind": "Status",
    "apiVersion": "v1",
    "metadata": {

    },
    "status": "Failure",
    "message": "Unauthorized",
    "reason": "Unauthorized",
    "code": 401
    }

    参考

  • kube-apiserver

  • kubernetes 组件

]]>
+ + + + + Kubernetes + + + + + + + k8s + + api-server + + + +
+ + + + + [Kubernetes] Kubernetes 中的弹性伸缩以及自动扩容 + + /blog/2021/01/24/Kubernetes-Kubernetes-%E4%B8%AD%E7%9A%84%E5%BC%B9%E6%80%A7%E4%BC%B8%E7%BC%A9%E4%BB%A5%E5%8F%8A%E8%87%AA%E5%8A%A8%E6%89%A9%E5%AE%B9/ + + + + + + + Kubernetes + + + + + + + k8s + + 弹性伸缩 + + 自动扩容 + + + + + + + + + 2020 年终总结 + + /blog/2021/01/12/2020-%E5%B9%B4%E7%BB%88%E6%80%BB%E7%BB%93/ + + 一直以来自己是不喜欢将一些总结放到博客里来的,感觉这个还是挺私密的,是自己一年的发展回顾。但是看了很多大佬的博客,他们都很擅于总结自己的一年,并且也会将之发到自己的博客上,我感觉这样也挺好的。自己之前都是将这些总结放到本地存储,但这样有时写了一会就不想去写了,很容易虎头蛇尾。因此我决定以后可以将一些总结,感触什么的放到博客里,以此来监督自己一直坚持下去~

2020,一个不平凡的一年,这整年人人都基本是带着口罩过来的,直到现在还是无法摆脱带口罩,每天出行仍需带着上地铁,进公司。在年初,因为疫情影响,相信很多人都是被困在家远程办公。刚开始在家办公,自己还是不适应的,没有公司的那种开发氛围,很多需求也不能面对面及时的沟通得以解决,这样还是挺不方便的。但是后来,随着在家办公的时间长了,感觉在家办公也不错,至少节省了上下班通勤路上的时间,每天从床上爬起来就可以投入工作,这种感觉还是挺好的。当然这样对于大多数人工作效率肯定是很低的,所以公司还是会尽量要求员工在家隔离完就需要回公司办公了,因此自己大概在今年3月份回到联想大厦办公了。

其实自己在年初的时候给自己的2020定了一些计划的,但是关于实现与否,还真是偏差甚远。首先是打算这一年换一份工作的,最好是NLP算法工程师相关的工作。在今年的前三个月里,自己还是很认真的在学习NLP相关的知识,但是后面发现自己还是很难去找这相关的工作,加上后面在联想又大部分时间在做开发相关的工作,所以后面也就没再学习了。关于跳槽,从今年8月份开始更新几个网站的简历,然后也是8月份开始陆续接到了很多猎头的电话,也面试了很多了公司,最终拿了几个offer,待遇什么的较联想这边也有一定的涨幅。最后选择了一家互联网+金融的公司,信也科技,但不是算法相关的岗位,不过也挺符合自己的发展方向的,目前主要是机器学习容器云平台开发,主要是
Python / Go 作为技术栈, 基于 Kubernetes / Docker 打造基于云原生上传数据集,标注,特征提取,训练以及模型部署一体化的机器学习平台。

]]>
+ + + +
+ + + + + [GO] — 解析 GOROOT、GOPATH 以及 ubuntu 中构建 golang 项目 + + /blog/2020/12/27/GO-%E2%80%94-%E8%A7%A3%E6%9E%90-GOROOT%E3%80%81GOPATH-%E4%BB%A5%E5%8F%8A-UBUNTU-%E4%B8%AD%E6%9E%84%E5%BB%BA-golang-%E9%A1%B9%E7%9B%AE/ + + + + + + + GO + + + + + + + gopath + + go-modules + + + + + + + + + [GO] golang学习之interface接口 + + /blog/2020/12/26/GO-%E2%80%94-Golang%E5%AD%A6%E4%B9%A0%E4%B9%8Binterface%E6%8E%A5%E5%8F%A3/ + + + + + + + GO + + + + + + + interface + + + + + + + + + [Kubernetes] 认识一下Kubernetes + + /blog/2020/10/29/Kubernetes-%E8%AE%A4%E8%AF%86%E4%B8%80%E4%B8%8BKubernetes/ + + 有哪些组件

Kubernetes 集群分为两个部分:

  • Kubernetes 控制平面
  • (工作)节点

其中控制平面的组件有:

  • Etcd 分布式持久化存储
  • API Server
  • Kube Scheduler
  • Kube Controller

运行容器任务依赖于每个工作节点上运行的组件,包括:

  • Kubelet
  • Kubelet 服务代理(kube proxy)
  • 容器运行时(docker,rkt,containerd或者其他)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
class Solution:
# 返回[a,b] 其中ab是出现一次的两个数字
def FindNumsAppearOnce(self, array):
# write code here
if array is None:
return

hash_map = {}
for num in array:
if num in hash_map:
hash_map[num] += 1
else:
hash_map[num] = 1

res = [num for num in hash_map.keys() if hash_map[num] == 1]
return res

代码测试:

1
2
3
4
5
if __name__ == "__main__":
print(Solution().FindNumsAppearOnce([2, 3, 1, 5, 1, 3, 6, 11, 6, 0, 11, 5]))

>>> [2, 0]

]]>
+ + + + + 刷题 + + + + + + + 剑指offer + + + +
+ + + + + 剑指offer 第八天 + + /blog/2020/07/20/%E5%89%91%E6%8C%87offer-%E7%AC%AC%E5%85%AB%E5%A4%A9/ + + JZ59 按之字形顺序打印二叉树

题目描述:

请实现一个函数按照之字形打印二叉树,即第一行按照从左到右的顺序打印,第二层按照从右至左的顺序打印,第三行按照从左到右的顺序打印,其他行以此类推。

解法思路:
这道题其实是昨天最后一道题JZ60的升级版,其实也就是层次遍历二叉树(BFS)。层次遍历思想可以参见上一道题,只是此题需要结合二叉树的深度depth进行解题。在每次需要打印的地方,当深度depth对2取余,为0则从左到右打印,为1则反转打印。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
class TreeNode:
def __init__(self, x):
self.val = x
self.left = None
self.right = None


class Solution:
def Print(self, pRoot):
# write code here
if pRoot is None:
return []

depth = 0
node_queue = [pRoot]
res = []

while node_queue:
val = []
length = len(node_queue)
for i in range(length):
current = node_queue.pop(0)
val.append(current.val)

if current.left:
node_queue.append(current.left)

if current.right:
node_queue.append(current.right)

if depth % 2 == 0:
res.append(val)
else:
res.append(list(reversed(val)))

depth += 1

return res

代码测试:

1
2
3
4
5
6
7
8
9
10
11
12
if __name__ == "__main__":
root = TreeNode(0)
root.left = TreeNode(1)
root.right = TreeNode(2)
root.left.left = TreeNode(3)
root.left.right = TreeNode(4)
root.right.left = TreeNode(5)
root.right.left.left = TreeNode(6)

print(Solution().Print(root))

>>> [[0], [2, 1], [3, 4, 5], [6]]

JZ58 对称的二叉树

题目描述:

请实现一个函数,用来判断一棵二叉树是不是对称的。注意,如果一个二叉树同此二叉树的镜像是同样的,定义其为对称的。

解法思路:

1
2
3
4
5
6
7
8
9
10
11
class TreeNode:
def __init__(self, x):
self.val = x
self.left = None
self.right = None


class Solution:
def isSymmetrical(self, pRoot):
# write code here
pass

代码测试:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
if __name__ == "__main__":
num = 1
matrix = [[0 for i in range(4)] for j in range(4)]
for i in range(4):
for j in range(4):
matrix[i][j] = num
num += 1

print(Solution().printMatrix(matrix))
print(Solution().printMatrix([[1, 2], [3, 4], [5, 6], [7, 8], [9, 10]]))

>>> [1, 2, 3, 4, 8, 12, 16, 15, 14, 13, 9, 5, 6, 7, 11, 10]
[1, 2, 4, 6, 8, 10, 9, 7, 5, 3]


JZ38 二叉树的下一个结点

题目描述:

给定一个二叉树和其中的一个结点,请找出中序遍历顺序的下一个结点并且返回。注意,树中的结点不仅包含左右子结点,同时包含指向父结点的指针。

解法思路:

1
2
3
4
5
6
7
8
9
10
11
class TreeNode:
def __init__(self, x):
self.val = x
self.left = None
self.right = None


class Solution:
def GetNext(self, pNode):
# write code here
pass

代码测试:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
if __name__ == "__main__":
root = TreeNode(0)
root.left = TreeNode(1)
root.right = TreeNode(2)
root.left.left = TreeNode(3)
root.left.right = TreeNode(4)
root.right.left = TreeNode(5)
root.right.left.left = TreeNode(6)

print(Solution().TreeDepth(root))
print(Solution2().TreeDepth(root))

>>> 4
4

JZ38 平衡二叉树

题目描述:

输入一棵二叉树,判断该二叉树是否是平衡二叉树。

在这里,我们只需要考虑其平衡性,不需要考虑其是不是排序二叉树

解法思路:

1
2
3
4
5
6
7
8
9
10
11
12
class TreeNode:
def __init__(self, x):
self.val = x
self.left = None
self.right = None


class Solution:
def IsBalanced_Solution(self, pRoot):
# write code here
pass

代码测试:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
if __name__ == "__main__":
root = TreeNode(0)
root.left = TreeNode(1)
root.right = TreeNode(2)
root.left.left = TreeNode(3)
root.left.right = TreeNode(4)
root.right.left = TreeNode(5)
root.right.left.left = TreeNode(6)

print(Solution().TreeDepth(root))
print(Solution2().TreeDepth(root))

>>> 4
4
]]>
+ + + + + 刷题 + + + + + + + 剑指offer + + + +
+ + + + + 剑指offer 第七天 + + /blog/2020/07/19/%E5%89%91%E6%8C%87offer-%E7%AC%AC%E4%B8%83%E5%A4%A9/ + + JZ19 顺时针打印矩阵

题目描述:

输入一个矩阵,按照从外向里以顺时针的顺序依次打印出每一个数字,例如,如果输入如下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
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
class Solution:
# matrix类型为二维列表,需要返回列表
def printMatrix(self, matrix):
# write code here
top = 0
bottom = len(matrix)
left = 0
right = len(matrix[0])

res = []
# 判断是否越界
while top < bottom and left < right:
# 最上面一行,需向右打印
res.extend([matrix[top][c] for c in range(left, right)])
# 最右边一行,需向下打印
res.extend([matrix[r][right - 1] for r in range(top + 1, bottom)])
# 最下面一行,需向左打印
if bottom - top > 1:
res.extend([matrix[bottom - 1][c] for c in range(right - 2, left, -1)]) # 注意需要将右边那个值去除掉
# 最左边一行,需向上打印
if right - left > 1:
res.extend([matrix[r][left] for r in range(bottom - 1, top, -1)])

top += 1
bottom -= 1
left += 1
right -= 1

return res

代码测试:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
if __name__ == "__main__":
num = 1
matrix = [[0 for i in range(4)] for j in range(4)]
for i in range(4):
for j in range(4):
matrix[i][j] = num
num += 1

print(Solution().printMatrix(matrix))
print(Solution().printMatrix([[1, 2], [3, 4], [5, 6], [7, 8], [9, 10]]))

>>> [1, 2, 3, 4, 8, 12, 16, 15, 14, 13, 9, 5, 6, 7, 11, 10]
[1, 2, 4, 6, 8, 10, 9, 7, 5, 3]


JZ38 二叉树的深度

题目描述:

输入一棵二叉树,求该树的深度。从根结点到叶结点依次经过的结点(含根、叶结点)形成树的一条路径,最长路径的长度为树的深度。

解法思路:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
class TreeNode:
def __init__(self, x):
self.val = x
self.left = None
self.right = None


class Solution:
def TreeDepth(self, pRoot):
# write code here
if not pRoot:
return 0

x = pRoot

left = self.TreeDepth(pRoot.left)
right = self.TreeDepth(pRoot.right)

return max(left, right) + 1


class Solution2:
def TreeDepth(self, pRoot):
# write code here
if pRoot is None:
return 0
q = []
depth = 0
q.append(pRoot)
while len(q): # 队列为空时说明没有下一层
length = len(q)
for i in range(length): # 遍历层的每个节点看是否有子节点有则加入
current = q.pop(0) # current为当前遍历到的层中节点,取出,注意pop(-1)为默认,这里要pop(0),取出第一个,先入先出
if current.left:
q.append(current.left)
if current.right:
q.append(current.right)
depth += 1
return depth

代码测试:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
if __name__ == "__main__":
root = TreeNode(0)
root.left = TreeNode(1)
root.right = TreeNode(2)
root.left.left = TreeNode(3)
root.left.right = TreeNode(4)
root.right.left = TreeNode(5)
root.right.left.left = TreeNode(6)

print(Solution().TreeDepth(root))
print(Solution2().TreeDepth(root))

>>> 4
4

JZ60 把二叉树打印成多行

题目描述:

从上到下按层打印二叉树,同一层结点从左至右输出。每一层输出一行。

解法思路:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
class TreeNode:
def __init__(self, x):
self.val = x
self.left = None
self.right = None


class Solution:
# 返回二维列表[[1,2],[4,5]]
def Print(self, pRoot):
# write code here
if not pRoot:
return []

node_queue = [pRoot]
res = []
while node_queue:
val = []
length = len(node_queue)
for i in range(length):
current = node_queue.pop(0)
val.append(current.val)

if current.left:
node_queue.append(current.left)
if current.right:
node_queue.append(current.right)

res.append(val)

return res

代码测试:

1
2
3
4
5
6
7
8
9
10
11
12
if __name__ == "__main__":
root = TreeNode(8)
root.left = TreeNode(6)
root.right = TreeNode(10)
root.left.left = TreeNode(5)
root.left.right = TreeNode(7)
root.right.left = TreeNode(9)
root.right.right = TreeNode(11)

print(Solution().Print(root))

>>> [[8], [6, 10], [5, 7, 9, 11]]
]]>
+ + + + + 刷题 + + + + + + + 剑指offer + + + +
+ + + + + 剑指offer 第六天 + + /blog/2020/07/13/%E5%89%91%E6%8C%87offer-%E7%AC%AC%E5%85%AD%E5%A4%A9/ + + JZ6 旋转数组的最小数字

题目描述:

把一个数组最开始的若干个元素搬到数组的末尾,我们称之为数组的旋转。
输入一个非递减排序的数组的一个旋转,输出旋转数组的最小元素。
例如数组{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
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
class Solution:
def minNumberInRotateArray(self, rotateArray):
# write code here
if len(rotateArray) == 0:
return 0
left = 0
right = len(rotateArray) - 1
while left < right:
if rotateArray[left] < rotateArray[right]:
return rotateArray[left]

mid = (left + right) // 2
if rotateArray[mid] > rotateArray[left]:
left = mid + 1
elif rotateArray[mid] < rotateArray[right]:
right = mid
else:
left += 1

return rotateArray[left]

代码测试:

1
2
3
4
5
if __name__ == "__main__":
print(Solution().minNumberInRotateArray([1, 0, 1, 1, 1]))

>>> 0

JZ18 二叉树的镜像

题目描述:

操作给定的二叉树,将其变换为源二叉树的镜像。
二叉树的镜像定义如下:

 源二叉树    8   /  \  6   10 / \  / \5  7 9 11镜像二叉树     8   /  \  10   6 / \  / \11 9 7  5

解法思路:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
class TreeNode:
def __init__(self, x):
self.val = x
self.left = None
self.right = None


class Solution:
# 返回镜像树的根节点
def Mirror(self, root):
# write code here
if root is None:
return

root.left, root.right = \
self.Mirror(root.right), self.Mirror(root.left)

return root

def preOrder(self, root):
if root is None:
return

print(root.val, end=' ')
self.preOrder(root.left)
self.preOrder(root.right)

代码测试:

1
2
3
4
5
6
7
8
9
10
11
12
13
if __name__ == "__main__":
tree1 = TreeNode(8)
tree1.left = TreeNode(6)
tree1.right = TreeNode(10)
tree1.left.left = TreeNode(5)
tree1.left.right = TreeNode(7)
tree1.right.left = TreeNode(9)
tree1.right.right = TreeNode(11)

invert_tree = Solution().Mirror(tree1)
print(Solution().preOrder(invert_tree))

>>> 8 10 11 9 6 7 5 None

JZ23 二叉搜索树的后序遍历

题目描述:

输入一个整数数组,判断该数组是不是某二叉搜索树的后序遍历的结果。如果是则输出Yes,否则输出No。假设输入的数组的任意两个数字都互不相同。

解法思路:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
class Solution:
def VerifySquenceOfBST(self, sequence):
# write code here
if len(sequence) == 0:
return False

root = sequence[-1]
for index, value in enumerate(sequence):
if value > root:
break

for value in sequence[index: -1]:
if value < root:
return False

left = True
if index > 0:
left = self.VerifySquenceOfBST(sequence[:index])

right = True
if index < len(sequence) - 1:
right = self.VerifySquenceOfBST(sequence[index: -1])

return left and right

代码测试:

1
2
3
4
5
if __name__ == "__main__":
is_binary_tree = [1, 3, 5, 9, 12, 10, 7]
print(Solution().VerifySquenceOfBST(is_binary_tree))

>>> True

JZ67 剪绳子

题目描述:

给你一根长度为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

解法思路:

代码测试:

]]>
+ + + + + 刷题 + + + + + + + 剑指offer + + + +
+ + + + + 剑指offer 第五天 + + /blog/2020/07/13/%E5%89%91%E6%8C%87offer-%E7%AC%AC%E4%BA%94%E5%A4%A9/ + + JZ8 跳台阶

题目描述:

一只青蛙一次可以跳上1级台阶,也可以跳上2级。求该青蛙跳上一个n级的台阶总共有多少种跳法(先后次序不同算不同的结果)。

解法思路:

1
2
3
4
5
6
7
8
9
10
11
12
class Solution:
def jumpFloor(self, number):
# write code here
if number <= 2:
return number

res, counter = 1, 0
for i in range(1, number + 1):
res = res + counter
counter = res - counter

return res

代码测试:

1
2
3
4
5
if __name__ == "__main__":
print(Solution().jumpFloor(3))

>>> 3

JZ9 变态跳台阶

题目描述:

一只青蛙一次可以跳上1级台阶,也可以跳上2级……它也可以跳上n级。求该青蛙跳上一个n级的台阶总共有多少种跳法。

解法思路:

1
2
3
4
5
6
7
8
9
10
11
12
class Solution:
def jumpFloor(self, number):
# write code here
if number <= 2:
return number

curr, prev = 1, 1
for i in range(1, number):
curr = 2 * prev
prev = curr

return curr

代码测试:

1
2
3
4
if __name__ == "__main__":
print(Solution().jumpFloor(3))

>>> 4

JZ10 矩形覆盖

题目描述:

我们可以用21的小矩形横着或者竖着去覆盖更大的矩形。请问用n个21的小矩形无重叠地覆盖一个2*n的大矩形,总共有多少种方法?

解法思路:

1
2
3
4
5
6
7
8
9
10
11
12
class Solution:
def rectCover(self, number):
# write code here
if number <= 2:
return number

res, counter = 1, 0
for i in range(1, number + 1):
res = res + counter
counter = res - counter

return res

代码测试:

1
2
3
4
if __name__ == "__main__":
print(Solution().rectCover(4))

>>> 5

JZ21 栈的压入、弹出序列

题目描述:

输入两个整数序列,第一个序列表示栈的压入顺序,请判断第二个序列是否可能为该栈的弹出顺序。假设压入栈的所有数字均不相等。
例如序列1,2,3,4,5是某栈的压入顺序,序列4,5,3,2,1是该压栈序列对应的一个弹出序列,但4,3,5,1,2就不可能是该压栈序列的弹出序列。
(注意:这两个序列的长度是相等的)

解法思路:

1
2
3
4
class Solution:
def IsPopOrder(self, pushV, popV):
# write code here
pass

代码测试:

]]>
+ + + + + 刷题 + + + + + + + 剑指offer + + + +
+ + + + + 剑指offer 第四天 + + /blog/2020/07/11/%E5%89%91%E6%8C%87offer-%E7%AC%AC%E5%9B%9B%E5%A4%A9/ + + JZ4 重建二叉树

题目描述:

输入某二叉树的前序遍历和中序遍历的结果,请重建出该二叉树。假设输入的前序遍历和中序遍历的结果中都不含重复的数字。例如输入前序遍历序列 [1,2,4,7,3,5,6,8] 和中序遍历序列 [4,7,2,1,5,3,8,6] ,则重建二叉树并返回。

解法思路:
使用递归的方法求解。这道题需要对二叉树的性质比较了解,需要熟悉二叉树的几种遍历方式。

前序遍历是先遍历根节点,然后遍历左节点,最后遍历右节点(根左右)

中序遍历是先遍历左节点,然后遍历根节点,最后遍历右节点(左根右)

后序遍历是先遍历左节点,然后遍历右节点,最后遍历根节点(根左右)

本题给定前序遍历以及中序遍历的序列,可以知道前序遍历第一个值一定是根节点。而根节点在中序遍历中会把左右子树分成两半。因此本题的关键是找到根节点,然后将左右子树依次递归重建得到二叉树。

使用递归是需要结束条件的,当前序或中序遍历序列为None时,便可推出递归,得到二叉树。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
class TreeNode:
def __init__(self, x):
self.val = x
self.left = None
self.right = None


class Solution:
# 返回构造的TreeNode根节点
def reConstructBinaryTree(self, pre, tin):
if not pre or not tin:
return None

root = TreeNode(pre.pop(0))
index = tin.index(root.val)

root.left = self.reConstructBinaryTree(pre, tin[:index])
root.right = self.reConstructBinaryTree(pre, tin[index + 1:])

return root

def preOrder(self, root):
if root is None:
return

print(root.val, end=' ')
self.preOrder(root.left)
self.preOrder(root.right)

def InOrder(self, root):
if root is None:
return
self.InOrder(root.left)
print(root.val, end=' ')
self.InOrder(root.right)

def BackOrder(self, root):
if root is None:
return
self.BackOrder(root.left)
self.BackOrder(root.right)
print(root.val, end=' ')

本题只需写好reConstructBinaryTree这个方法,上面代码其他三个函数是用来前序、中序以及后序遍历重建得到二叉树的,以方便大家调试。
代码测试:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
if __name__ == "__main__":
pre = [1, 2, 4, 7, 3, 5, 6, 8]
tin = [4, 7, 2, 1, 5, 3, 8, 6]

reTree = Solution().reConstructBinaryTree(pre, tin)
print("前序遍历:")
Solution().preOrder(reTree)
print("\n")
print("中序遍历:")
Solution().InOrder(reTree)
print("\n")
print("后序遍历:")
Solution().BackOrder(reTree)

>>> 前序遍历:
1 2 4 7 3 5 6 8

中序遍历:
4 7 2 1 5 3 8 6

后序遍历:
7 4 2 5 8 6 3 1

JZ18 二叉树的镜像

题目描述:

操作给定的二叉树,将其变换为源二叉树的镜像。
二叉树的镜像定义如下:

 源二叉树    8   /  \  6   10 / \  / \5  7 9 11镜像二叉树     8   /  \  10   6 / \  / \11 9 7  5

解法思路:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
class TreeNode:
def __init__(self, x):
self.val = x
self.left = None
self.right = None


class Solution:
# 返回镜像树的根节点
def Mirror(self, root):
# write code here
if root is None:
return

root.left, root.right = \
self.Mirror(root.right), self.Mirror(root.left)

return root

def preOrder(self, root):
if root is None:
return

print(root.val, end=' ')
self.preOrder(root.left)
self.preOrder(root.right)

代码测试:

1
2
3
4
5
6
7
8
9
10
11
12
13
if __name__ == "__main__":
tree1 = TreeNode(8)
tree1.left = TreeNode(6)
tree1.right = TreeNode(10)
tree1.left.left = TreeNode(5)
tree1.left.right = TreeNode(7)
tree1.right.left = TreeNode(9)
tree1.right.right = TreeNode(11)

invert_tree = Solution().Mirror(tree1)
print(Solution().preOrder(invert_tree))

>>> 8 10 11 9 6 7 5 None

JZ23 二叉搜索树的后序遍历

题目描述:

输入一个整数数组,判断该数组是不是某二叉搜索树的后序遍历的结果。如果是则输出Yes,否则输出No。假设输入的数组的任意两个数字都互不相同。

解法思路:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
class Solution:
def VerifySquenceOfBST(self, sequence):
# write code here
if len(sequence) == 0:
return False

root = sequence[-1]
for index, value in enumerate(sequence):
if value > root:
break

for value in sequence[index: -1]:
if value < root:
return False

left = True
if index > 0:
left = self.VerifySquenceOfBST(sequence[:index])

right = True
if index < len(sequence) - 1:
right = self.VerifySquenceOfBST(sequence[index: -1])

return left and right

代码测试:

1
2
3
4
5
if __name__ == "__main__":
is_binary_tree = [1, 3, 5, 9, 12, 10, 7]
print(Solution().VerifySquenceOfBST(is_binary_tree))

>>> True

JZ67 剪绳子

题目描述:

给你一根长度为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

解法思路:

代码测试:

]]>
+ + + + + 刷题 + + + + + + + 剑指offer + + + +
+ + + + + 剑指offer 第三天 + + /blog/2020/07/08/%E5%89%91%E6%8C%87offer-%E7%AC%AC%E4%B8%89%E5%A4%A9/ + + JZ11 二进制中1的个数

题目描述:

输入一个整数,输出该数32位二进制表示中1的个数。其中负数用补码表示。

解法思路:

1
2
3
4
5
6
7
8
9
10
11
12
def NumberOf1(self, n):
# write code here
count = 0

if n < 0:
n = n & 0b11111111111111111111111111111111

while n != 0:
count += 1
n = n & (n - 1)

return count

代码测试:

1
2
3
4
if __name__ == "__main__":
print(Solution().NumberOf1(-11))

>>> 30

JZ27 字符串的排列

题目描述:

输入一个字符串,按字典序打印出该字符串中字符的所有排列。例如输入字符串abc,则打印出由字符a,b,c所能排列出来的所有字符串abc,acb,bac,bca,cab和cba。

输入一个字符串,长度不超过9(可能有字符重复),字符只包括大小写字母。

解法思路:

1
2
3
4
class Solution:
def Permutation(self, ss):
# write code here
pass

代码测试:

1

JZ47 求1 + 2 + 3 + … + n

题目描述:

求1+2+3+…+n,要求不能使用乘除法、for、while、if、else、switch、case等关键字及条件判断语句(A?B:C)。

解法思路:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
class Solution:
def Sum_Solution(self, n):
# write code here
res = n
try:
res % n
res += self.Sum_Solution(n - 1)
except ZeroDivisionError:
return 0

return res


class Solution2:
def Sum_Solution(self, n):
# write code here
res = n
tmp = (res and self.Sum_Solution(n - 1))
res += tmp

return res

代码测试:

1
2
3
4
5
6
if __name__ == "__main__":
print(Solution().Sum_Solution(5))
print(Solution2().Sum_Solution(6))

>>> 15
21

JZ51 构建乘积数组

题目描述:

给定一个数组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
2
3
4
class Solution:
def multiply(self, A):
# write code here
pass

代码测试:

]]>
+ + + + + 刷题 + + + + + + + 剑指offer + + + +
+ + + + + 剑指offer 第二天 + + /blog/2020/07/07/%E5%89%91%E6%8C%87offer%E7%AC%AC%E4%BA%8C%E5%A4%A9/ + + JZ49 把字符串转化成整数

题目描述:

将一个字符串转换成一个整数,要求不能使用字符串转换整数的库函数。 数值为0或者字符串不是一个合法的数值则返回0
输入描述:
输入一个字符串,包括数字字母符号,可以为空
输出描述:
如果是合法的数值表达则返回该数字,否则返回0

示例:
输入:
+2147483647
1a33
输出:
2147483647
0

解法思路:
使用了一个很巧妙的方法,用一个字典将字符串”0”-“9”与数字0 - 9做一个映射,然后再用数学上计算一个数字的公式得出这个数。比如:123 = (1 * 10 + 2 ) * 10 + 3。需要注意字符串开头的正负号,从而判断得到的数字是整数还是负数。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
class Solution:
def StrToInt(self, s):
# write code here
if len(s) == 0:
return 0

str2num = {
"0": 0, "1": 1, "2": 2, "3": 3, "4": 4,
"5": 5, "6": 6, "7": 7, "8": 8, "9": 9,
"+": 1, "-": -1
}

sum = 0
sign = 1
for c in s:
if c in str2num:
if c == "+":
sign = str2num["+"]
continue
if c == "-":
sign = str2num["-"]
continue
sum = sum * 10 + str2num[c]
else:
sum = 0
break

return sum * sign

代码测试:

1
2
3
4
5
if __name__ == "__main__":
s = "-98210"
print(Solution().StrToInt(s))

>>> 98210

JZ7 斐波那契数列

题目描述:

大家都知道斐波那契数列,现在要求输入一个整数n,请你输出斐波那契数列的第n项(从0开始,第0项为0,第1项是1)(n<=39)。

解法一思路:
直接根据数学公式f(n) = f(n - 1) + f(n - 2),截至条件是当n = 1, f(n) = 1n = 0, f(0) = 0。利用递归法进行求解,这种方法时间复杂度很大,为O(n^2),空间复杂度为O(1)

1
2
3
4
5
6
7
class Solution:
def Fibonacci(self, n):
# write code here
if n <= 1:
return n
else:
return self.Fibonacci(n-1) + self.Fibonacci(n-2)

解法二思路:

1
2
3
4
5
6
7
8
9
10
11
12
13
class Solution2:
def Fibonacci(self, n):
# write code here
if n <= 1:
return n

n1, n2, n3 = 0, 1, 0
for i in range(1, n):
n3 = n1 + n2
n1 = n2
n2 = n3

return n3

解法三思路:

1
2
3
4
5
6
7
8
9
10
11
12
class Solution3:
def Fibonacci(self, n):
# write code here
if n <= 1:
return n

sum, one = 1, 0
for i in range(1, n):
sum = sum + one
one = sum - one

return sum

代码测试:

1
2
3
4
5
6
7
8
if __name__ == "__main__":
print(Solution().Fibonacci(8))
print(Solution2().Fibonacci(8))
print(Solution3().Fibonacci(8))

>>> 21
>>> 21
>>> 21

JZ48 不用加减乘除做加法

题目描述:

写一个函数,求两个整数之和,要求在函数体内不得使用+、-、*、/四则运算符号。

解法思路:

1
2
3
4
class Solution:
def Add(self, num1, num2):
# write code here
pass

代码测试:

1

]]>
+ + + + + 刷题 + + + + + + + 剑指offer + + + +
+ + + + + 剑指offer 第一天 + + /blog/2020/07/06/%E5%89%91%E6%8C%87offer-%E7%AC%AC%E4%B8%80%E5%A4%A9/ + + JZ16 合并两个排序的链表

题目描述:

输入两个单调递增的链表,输出两个链表合成后的链表,当然我们需要合成后的链表满足单调不减规则。

解法一思路:
使用迭代的方法。先判断临界情况,依次判断输入的两个链表是否为空指针,如果有其中一个为空指针链表,则返回另一个有序的链表。

然后初始化一个新链表,依次比较两个有序链表的值,哪个链表的值较小,则新链表的指针指向该值。继续循环,依次比较,最终返回单调递增的新链表。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
class ListNode:
def __init__(self, x):
self.val = x
self.next = None


class Solution2:
# 返回合并后列表
def Merge(self, pHead1, pHead2):
# write code here
if pHead1 is None:
return pHead2
if pHead2 is None:
return pHead1

node = sorted_node = ListNode(0)

while pHead1 and pHead2:
if pHead1.val < pHead2.val:
node.next = pHead1
pHead1 = pHead1.next
else:
node.next = pHead2
pHead2 = pHead2.next
node = node.next

if pHead1 or pHead2:
node.next = pHead1 or pHead2

return sorted_node.next

def travel_list(self, node):
while node is not None:
print(node.val, end=" ")
node = node.next

解法二思路:
使用递归的方法。大体思路同上,先判断临界情况,依次判断输入的两个链表是否为空指针,如果有其中一个为空指针链表,则返回另一个有序的链表。

然后依次比较两个有序链表的值,哪个链表的值较小,则将该节点赋值给新链表。使用递归,直至其中一个链表为None,最终返回和并得到的单调递增链表。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
class ListNode:
def __init__(self, x):
self.val = x
self.next = None

class Solution:
# 返回合并后列表
def Merge(self, pHead1, pHead2):
# write code here
if pHead1 is None:
return pHead2
if pHead2 is None:
return pHead1

if pHead1.val < pHead2.val:
sorted_list = pHead1
sorted_list.next = self.Merge(pHead1.next, pHead2)
else:
sorted_list = pHead2
sorted_list.next = self.Merge(pHead1, pHead2.next)

return sorted_list

def travel_list(self, node):
while node is not None:
print(node.val, end=" ")
node = node.next

代码测试:

1
2
3
4
5
6
7
8
9
10
11
12
13
if __name__ == "__main__":
node_1 = ListNode(0)
node_1.next = ListNode(4)
node_1.next.next = ListNode(10)
node_2 = ListNode(2)
node_2.next = ListNode(3)
node_2.next.next = ListNode(12)
solu_1 = Solution()
# print(solu_1.travel_list(solu_1.Merge(node_1, node_2)))
solu_2 = Solution2()
print(solu_2.travel_list(solu_2.Merge(node_1, node_2)))

>>> 0 2 3 4 10 12 None

JZ14 链表中倒数第k个结点

题目描述:

输入一个链表,输出该链表中倒数第k个结点。

解法一思路:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
lass ListNode:
def __init__(self, x):
self.val = x
self.next = None


class Solution:
# 时间复杂度: O(n)
# 空间复杂度: O(n)
def FindKthToTail(self, head, k):
# write code here
res = []

while head is not None:
res.insert(0, head.val)
head = head.next

if len(res) < k or k < 1:
return

return res[k-1]

def travel_listNode(self, listNode):
while listNode:
print(listNode.val, end=" ")
listNode = listNode.next

解法二思路:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
class Solution2:
# 时间复杂度: O(n)
# 空间复杂度: O(1)
def FindKthToTail(self, head, k):
# write code here
if k < 0 or head is None:
return

slow, fast = head, head
count = 0
while fast.next is not None:
fast = fast.next
if count >= k - 1:
slow = slow.next
count += 1

if count >= k - 1:
return slow.val

return None

代码测试:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
if __name__ == "__main__":
curr = head = ListNode(0)
head.next = ListNode(1)
head = head.next
head.next = ListNode(2)
head = head.next
head.next = ListNode(3)
head = head.next
head.next = ListNode(4)

print(Solution().travel_listNode(curr))
print(Solution().FindKthToTail(curr, 5))
print(Solution2().FindKthToTail(curr, 5))

>>> 0 1 2 3 4 None
>>> 0
>>> 0

JZ15 反转链表

题目描述:

输入一个链表,反转链表后,输出新链表的表头。

解法思路:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
class ListNode:
def __init__(self, x):
self.val = x
self.next = None


class Solution:
# 返回ListNode
def ReverseList(self, pHead):
# write code here
if not pHead or pHead.next is None:
return pHead

curr, prev = pHead, None
while curr:
tmp = curr.next
curr.next = prev
prev = curr
curr = tmp

return prev

代码测试:

1
2
3
4
5
6
7
8
9
10
11
12
13
if __name__ == "__main__":
curr = head = ListNode(0)
head.next = ListNode(1)
head = head.next
head.next = ListNode(2)
head = head.next
head.next = ListNode(3)
head = head.next
# print(head)
print(curr)

res = Solution().ReverseList(curr)
print(res)

JZ13 从尾到头打印链表

题目描述:

输入一个链表,按链表从尾到头的顺序返回一个ArrayList。

解法思路:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
class ListNode:
def __init__(self, x):
self.val = x
self.next = None


class Solution:
# 返回从尾部到头部的列表值序列,例如[1,2,3]
def printListFromTailToHead(self, listNode):
# write code here
res = []
while listNode:
res.insert(0, listNode.val)
listNode = listNode.next

return res

def travel_listNode(self, listNode):
while listNode:
print(listNode.val, end=" ")
listNode = listNode.next

代码测试:

1
2
3
4
5
6
7
8
9
10
11
12
if __name__ == "__main__":
curr = head = ListNode(0)
head.next = ListNode(1)
head = head.next
head.next = ListNode(2)
head = head.next
head.next = ListNode(3)
head = head.next
head.next = ListNode(4)

print(Solution().travel_listNode(curr))
print(Solution().printListFromTailToHead(curr))
]]>
+ + + + + 刷题 + + + + + + + 剑指offer + + + +
+ + + + + NLP(1)文本分类知识梳理 + + /blog/2020/06/27/NLP%EF%BC%881%EF%BC%89%E6%96%87%E6%9C%AC%E5%88%86%E7%B1%BB%E7%9F%A5%E8%AF%86%E6%A2%B3%E7%90%86/ + + + + + + + NLP + + 文本分类 + + + + + + + 文本分类 + + + + + + + + + Python之函数式编程模块(2) + + /blog/2020/06/19/Python%E4%B9%8B%E5%87%BD%E6%95%B0%E5%BC%8F%E7%BC%96%E7%A8%8B%E6%A8%A1%E5%9D%97%EF%BC%882%EF%BC%89/ + + 这篇文章主要是讲解一些函数式编程常用的模块,比如:itertools, functools以及operator

一、itertools –用以创建迭代器的模块

二、functools – 高阶函数可调用对象上的操作

三、operator – 标准运算符替代函数

在函数式编程中,我们经常需要把算术运算符当作函数使用,因此可以借助operator模块。operator 模块提供了一套与Python的内置运算符对应的高效率函数。例如,operator.add(x, y) 与表达式 x+y 相同。

operator 模块为多个算术运算符提供了对应的函数,从而避免编写
lambda a, b: a * b 这种平凡的匿名函数。这两种做法具体如下:

  • 使用lambda a, b: a * b匿名函数来计算阶乘:
1
2
3
4
5
6
7
8
>>> from functools import reduce
>>> from operator import mul
>>> def fact(n):
... return reduce(mul, range(1, n+1))
...
>>> fact(5)
120

  • 使用operator.mul函数来计算阶乘:
1
2
3
4
5
6
7
8
>>> from functools import reduce
>>> from operator import mul
>>> def fact(n):
... return reduce(mul, range(1, n+1))
...
>>> fact(5)
120

operator 模块中还有一类函数,能替代从系列中取出元素或读取对象属性的lambda表达式:

]]>
+ + + + + Python + + + + + + + 函数式编程 + + 高级语法 + + + +
+ + + + + Python之函数式编程模块(1) + + /blog/2020/06/19/Python%E4%B9%8B%E5%87%BD%E6%95%B0%E5%BC%8F%E7%BC%96%E7%A8%8B%E6%A8%A1%E5%9D%97/ + + 一、编程方式介绍

一般编程语言支持通过以下几种方式来解决具体的问题:

  • 大多数的编程语言都是过程式的,也就是我们常说的面向过程的编程方式。而所谓程序是指令的列表,告诉计算机如何处理程序的输入。C、Pascal甚至Unix shell都是过程式语言。
  • 然后有一些编程语言是声明式的,主要是你需要编写一个用来描述待解决问题的说明,然后这个语言的具体实现会指明怎样高效的进行计算并解决问题。SQL 可能是你最熟悉的声明式语言了。 一个 SQL 查询语句描述了你想要检索的数据集,并且 SQL 引擎会决定是扫描整张表还是使用索引,应该先执行哪些子句等等。
  • 面向对象编程语言会操作一组对象。其中对象拥有内部状态,并能够以某种方式支持请求和修改这个内部状态的方法。Smalltalk 和 Java 都是面向对象的语言。C++ 和 Python 支持面向对象编程,但并不强制使用面向对象特性。
  • 函数式编程则是将一个问题分解成一系列函数。理想情况下,函数只接受输入并产生输出,没有任何内部状态会影响为给定输入产生的输出。众所周知的函数式语言包括ML家族(标准ML、OCaml和其他变体)和Haskell。

一般语言设计者在设计语言时,会选择侧重强调一种特定的编程方式,但这会让以不同方式来编写程序变得困难。因此有些语言就被设计成多范式语言,用以支持以上几种不同的编程方式。其中Lisp,C++ 和 Python 都是多范式语言;使用这些语言,你可以编写主要为过程式,面向对象或者函数式的程序和函数库。在大型程序中,不同的部分可能会采用不同的方式编写;比如 GUI 可能是面向对象的而处理逻辑则是过程式或者函数式。

这篇文章主要是来讲解函数式编程,因此接下来主要围绕函数式编程进行展开。

二、函数式编程

2.1 定义

函数式编程:即为给定输入,输入会流经一系列函数,每个函数接收输入并输出结果。并且这个过程,在每个函数内部并不会修改全局变量或者有其他副作用。函数式编程允许把函数本身作为参数传入另一个函数,还允许返回一个函数。

2.2 特点

函数式风格有其理论和实践上的优点:

  • 形式证明
  • 模块化
  • 组合性
  • 易于调试和测试

三、函数式编程实践

3.1

]]>
+ + + + + Python + + + + + + + 函数式编程 + + 高级语法 + + + +
+ + + + + My first post + + /blog/2020/06/18/My-first-post/ + + + + + + + + + + +
diff --git a/page/2/index.html b/page/2/index.html new file mode 100644 index 0000000..4794ef2 --- /dev/null +++ b/page/2/index.html @@ -0,0 +1,1061 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + LuckyCrise + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ + + + + + +
+ +
+ +
+ +
+
+ +
+
+
+ + + + + +
+ + + +
+ +
+ + + +
+ + + +
+ + + +
+ + + + + + + + + + + + + + + + + +
+
+
+
+
+ + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/page/3/index.html b/page/3/index.html new file mode 100644 index 0000000..678ccf6 --- /dev/null +++ b/page/3/index.html @@ -0,0 +1,965 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + LuckyCrise + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ + + + + + +
+ +
+ +
+ +
+
+ +
+
+
+ + + + + + + + + + + + + +
+ + + +
+ + + + + +
+ + + +
+ + + + + + + +
+
+
+
+
+ + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/placeholder b/placeholder deleted file mode 100644 index e69de29..0000000 diff --git a/search.xml b/search.xml new file mode 100644 index 0000000..54c7016 --- /dev/null +++ b/search.xml @@ -0,0 +1,961 @@ + + + + 如何使用 hexo 新建文章 + /blog/2024/09/04/hello-world/ + 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.

+

Quick Start

Create a new post

$ hexo new "My New Post"
+ +

More info: Writing

+

Run server

$ hexo server
+ +

More info: Server

+

Generate static files

$ hexo generate
+ +

More info: Generating

+

Deploy to remote sites

$ hexo deploy
+ +

More info: Deployment

+]]>
+
+ + [GO] golang中优雅设置参数默认值 + /blog/2023/04/13/GO-golang%E4%B8%AD%E4%BC%98%E9%9B%85%E8%AE%BE%E7%BD%AE%E5%8F%82%E6%95%B0%E9%BB%98%E8%AE%A4%E5%80%BC/ + 前言

今天在使用 golang 重构 python 站点时,遇到了一个有趣的事情。就是在 python 函数中参数是可以设置默认值的,这样在函数调用时,就不需要每个参数都传一个值,其实这也是变相的实现重载功能。但是我发现在 golang 中参数是不能设置默认值的,但是基于程序员的直觉,相信此事没那么简单,于是抱着打破沙锅问到底的态度,就有了这篇文章。

+

不设置默认值带来的不便

首先,通过一个例子,说明我在编码过程中遇到的问题。对于平台后端开发工程师来说,会经常遇到以下场景:
通过

+
    +
  • 通过多种条件查询数据库记录,比如:select * from user where user_name in (xxx, xxx, xx) and user_region = “shanghai” order by id desc;
  • +
  • 需要在不同功能模块做以上方式查询。
  • +
+

基于此,我将这些查询方式抽象成一个方法,之后所有的功能模块,都可以使用该方法进行多条件联合查询数据记录,具体抽象如下:

+
func DBQueryAllWithConditions(ctx context.Context, orderBy map[string]string, eqFilters map[string]interface{}, inFilters map[string]interface{}, likeFilters map[string]string) {

}
+ +

研读开源代码的优雅实现

改进自己的代码

总结

]]>
+ + GO + + + golang + +
+ + [Kubernetes] Kubernetes 核心组件之 kube-apiserver + /blog/2021/11/15/Kubernetes-Kubernetes-%E6%A0%B8%E5%BF%83%E7%BB%84%E4%BB%B6%E4%B9%8B-kube-apiserver/ + kube-apiserverKubernetes 最重要的核心组件之一,主要能提供的功能如下:

+
    +
  • 给集群其他组件提供数据交互以及通信枢纽功能,以RESTful API 的形式提供其他组件查询,修改集群状态的 CURD(Create,Read,Update,Detele)接口,然后将状态储存到 etcd 中;
  • +
  • 为用户请求接入认证,授权以及准入控制等功能;
  • +
  • 并且可以用来处理乐观锁, 当有并发更新的情况, 对对象做更改就不会被其他客户端覆盖。 + +
  • +
+

如何部署

工作原理

kube-apiserver 提供了 KubernetesREST API,实现了认证、授权、准入控制等安全校验功能,同时也负责集群状态的存储操作(通过 etcd)。

+

认证

授权

准入控制

API 访问示例

kube-apiserver 提供了为每种语言提供了 SDK,方便用户访问集群其他组件,以及将数据存储或更新到etcd中,如下:

+ +

kubectl 访问

    +
  • 查询 kube-apiserver 支持API的版本

    +
    $ kubectl api-versions
    admissionregistration.k8s.io/v1
    admissionregistration.k8s.io/v1beta1
    apiextensions.k8s.io/v1
    apiextensions.k8s.io/v1beta1
    apps/v1

    ...

    scheduling.k8s.io/v1
    scheduling.k8s.io/v1beta1
    storage.k8s.io/v1
    storage.k8s.io/v1beta1
    traefik.containo.us/v1alpha1
    v1
    xgboostjob.kubeflow.org/v1

  • +
  • 查询 kube-apiserver 支持API的资源对象

    +
    $ kubectl api-resources
    NAME SHORTNAMES APIGROUP NAMESPACED KIND
    bindings true Binding
    componentstatuses cs false ComponentStatus
    configmaps cm true ConfigMap

    ...

    tlsoptions traefik.containo.us true TLSOption
    tlsstores traefik.containo.us true TLSStore
    traefikservices traefik.containo.us true TraefikService
    xgboostjobs xgboostjob.kubeflow.org true XGBoostJob

  • +
  • 查看 kube-apiserverv1/namepsace 信息

    +
    $ kubectl get --raw /api/v1/namespaces
    {"kind":"NamespaceList","apiVersion":"v1","metadata":{"selfLink":"/api/v1/namespaces","resourceVersion":"190115288"},"items":[{"metadata":{"name":"airflow","selfLink":"/api/v1/namespaces/airflow","uid":"f4756c7a-8bd7-4988-a69c-c849a3c035be","resourceVersion":"79499605","creationTimestamp":"2021-05-06T07:39:19Z","managedFields":[{"manager":"kubectl-create","operation":"Update","apiVersion":"v1","time":"2021-05-06T07:39:19Z","fieldsType":"FieldsV1","fieldsV1":{"f:status":{"f:phase":{}}}}]},"spec":{"finalizers":["kubernetes"]},"status":{"phase":"Active"}},{"metadata":{"name":"crise","selfLink":"/api/v1/namespaces/crise","uid":"6f943c7a-8419-4c95-bf5a-2972f3631aab","resourceVersion":"155793497","creationTimestamp":"2021-09-26T05:09:22Z","managedFields":[{"manager":"kubectl-create","operation":"Update","apiVersion":"v1","time":"2021-09-26T05:09:22Z","fieldsType":"FieldsV1","fieldsV1":{"f:status":{"f:phase":{}}}}]},"spec":{"finalizers":["kubernetes"]},"status":{"phase":"Active"}},{"metadata":{"name":"default","selfLink":"/api/v1/namespaces/default","uid":"545db544-c735-4d06-a600-981144f245a8","resourceVersion":"157","creationTimestamp":"2020-11-12T07:25:33Z","managedFields":[{"manager":"kube-apiserver","operation":"Update","apiVersion":"v1","time":"2020-11-12T07:25:33Z","fieldsType":"FieldsV1","fieldsV1":{"f:status":{"f:phase":{}}}}]},"spec":{"finalizers":["kubernetes"]},"status":{"phase":"Active"}},{"metadata":{"name":"elastic","selfLink":"/api/v1/namespaces/elastic","uid":"adcddefd-2a71-4b65-af74-ec4d5ac854b4","resourceVersion":"132059434","creationTimestamp":"2021-08-10T08:36:48Z","labels":{"name":"elastic"},"managedFields":[{"manager":"Go-http-client","operation":"Update","apiVersion":"v1","time":"2021-08-10T08:36:48Z","fieldsType":"FieldsV1","fieldsV1":{"f:metadata":{"f:labels":{".":{},"f:name":{}}},"f:status":{"f:phase":{}}}}]},"spec":{"finalizers":["kubernetes"]},"status":{"phase":"Active"}},{"metadata":{"name":"kafka","selfLink":"/api/v1/namespaces/kafka","uid":"82f78a4a-b135-49af-a6d2-34b162deff34","resourceVersion":"126083706","creationTimestamp":"2021-07-30T06:28:47Z","labels":{"name":"kafka"},"managedFields":[{"manager":"Go-http-client","operation":"Update","apiVersion":"v1","time":"2021-07-30T06:28:47Z","fieldsType":"FieldsV1","fieldsV1":{"f:metadata":{"f:labels":{".":{},"f:name":{}}},"f:status":{"f:phase":{}}}}]},"spec":{"finalizers":["kubernetes"]},"status":{"phase":"Active"}},{"metadata":{"name":"kube-node-lease","selfLink":"/api/v1/namespaces/kube-node-lease","uid":"16073100-6a4c-4275-9cb4-914d16e92dd9","resourceVersion":"43","creationTimestamp":"2020-11-12T07:25:32Z","managedFields":[{"manager":"kube-apiserver","operation":"Update","apiVersion":"v1","time":"2020-11-12T07:25:32Z","fieldsType":"FieldsV1","fieldsV1":{"f:status":{"f:phase":{}}}}]},"spec":{"finalizers":["kubernetes"]},"status":{"phase":"Active"}},{"metadata":{"name":"kube-public","selfLink":"/api/v1/namespaces/kube-public","uid":"f6077460-b5ab-4250-ad00-bd7a32745873","resourceVersion":"41","creationTimestamp":"2020-11-12T07:25:32Z","managedFields":[{"manager":"kube-apiserver","operation":"Update","apiVersion":"v1","time":"2020-11-12T07:25:32Z","fieldsType":"FieldsV1","fieldsV1":{"f:status":{"f:phase":{}}}}]},"spec":{"finalizers":["kubernetes"]},"status":{"phase":"Active"}},{"metadata":{"name":"kube-system","selfLink":"/api/v1/namespaces/kube-system","uid":"4671dc1b-9f93-4c23-be43-65579ff03293","resourceVersion":"1051","creationTimestamp":"2020-11-12T07:25:32Z","annotations":{"kubectl.kubernetes.io/last-applied-configuration":"{\"apiVersion\":\"v1\",\"kind\":\"Namespace\",\"metadata\":{\"annotations\":{},\"name\":\"kube-system\"}}\n"},"managedFields":[{"manager":"kube-apiserver","operation":"Update","apiVersion":"v1","time":"2020-11-12T07:25:32Z","fieldsType":"FieldsV1","fieldsV1":{"f:status":{"f:phase":{}}}},{"manager":"kubectl-client-side-apply","operation":"Update","apiVersion":"v1","time":"2020-11-12T07:29:44Z","fieldsType":"FieldsV1","fieldsV1":{"f:metadata":{"f:annotations":{".":{},"f:kubectl.kubernetes.io/last-applied-configuration":{}}}}}]},"spec":{"finalizers":["kubernetes"]},"status":{"phase":"Active"}},{"metadata":{"name":"kubeflow-operators","selfLink":"/api/v1/namespaces/kubeflow-operators","uid":"7a506123-310a-48b7-8c4c-ea95238ed559","resourceVersion":"31999589","creationTimestamp":"2021-01-28T09:08:10Z","managedFields":[{"manager":"kubectl-create","operation":"Update","apiVersion":"v1","time":"2021-01-28T09:08:10Z","fieldsType":"FieldsV1","fieldsV1":{"f:status":{"f:phase":{}}}}]},"spec":{"finalizers":["kubernetes"]},"status":{"phase":"Active"}},{"metadata":{"name":"monitoring","selfLink":"/api/v1/namespaces/monitoring","uid":"28f94d9b-781a-4503-8704-05be7fc0b03f","resourceVersion":"1932","creationTimestamp":"2020-11-12T07:34:49Z","annotations":{"kubectl.kubernetes.io/last-applied-configuration":"{\"apiVersion\":\"v1\",\"kind\":\"Namespace\",\"metadata\":{\"annotations\":{},\"name\":\"monitoring\"}}\n"},"managedFields":[{"manager":"kubectl-client-side-apply","operation":"Update","apiVersion":"v1","time":"2020-11-12T07:34:49Z","fieldsType":"FieldsV1","fieldsV1":{"f:metadata":{"f:annotations":{".":{},"f:kubectl.kubernetes.io/last-applied-configuration":{}}},"f:status":{"f:phase":{}}}}]},"spec":{"finalizers":["kubernetes"]},"status":{"phase":"Active"}},{"metadata":{"name":"portainer","selfLink":"/api/v1/namespaces/portainer","uid":"65ce6ed6-be89-4da5-86da-8a5decf8b190","resourceVersion":"45415995","creationTimestamp":"2021-02-25T08:26:29Z","annotations":{"kubectl.kubernetes.io/last-applied-configuration":"{\"apiVersion\":\"v1\",\"kind\":\"Namespace\",\"metadata\":{\"annotations\":{},\"name\":\"portainer\"}}\n"},"managedFields":[{"manager":"kubectl-client-side-apply","operation":"Update","apiVersion":"v1","time":"2021-02-25T08:26:29Z","fieldsType":"FieldsV1","fieldsV1":{"f:metadata":{"f:annotations":{".":{},"f:kubectl.kubernetes.io/last-applied-configuration":{}}},"f:status":{"f:phase":{}}}}]},"spec":{"finalizers":["kubernetes"]},"status":{"phase":"Active"}},{"metadata":{"name":"rook-ceph","selfLink":"/api/v1/namespaces/rook-ceph","uid":"e4756739-9b75-43ac-8870-60191e336917","resourceVersion":"1716232","creationTimestamp":"2020-11-16T07:37:55Z","managedFields":[{"manager":"kubectl-create","operation":"Update","apiVersion":"v1","time":"2020-11-16T07:37:55Z","fieldsType":"FieldsV1","fieldsV1":{"f:status":{"f:phase":{}}}}]},"spec":{"finalizers":["kubernetes"]},"status":{"phase":"Active"}},{"metadata":{"name":"traefik-system","selfLink":"/api/v1/namespaces/traefik-system","uid":"ed85f7ef-2805-4ba7-84d1-5ae430471202","resourceVersion":"1381","creationTimestamp":"2020-11-12T07:31:22Z","managedFields":[{"manager":"kubectl-create","operation":"Update","apiVersion":"v1","time":"2020-11-12T07:31:22Z","fieldsType":"FieldsV1","fieldsV1":{"f:status":{"f:phase":{}}}}]},"spec":{"finalizers":["kubernetes"]},"status":{"phase":"Active"}}]}

    +
  • +
  • 通过启动 proxy 获取集群配置信息

    +
    $ kubectl proxy --port=8081 & curl http://localhost:8081/api/
    {
    "kind": "APIVersions",
    "versions": [
    "v1"
    ],
    "serverAddressByClientCIDRs": [
    {
    "clientCIDR": "0.0.0.0/0",
    "serverAddress": "10.114.1.100:6443"
    }
    ]
    }
    +
  • +
  • 查看集群各组件信息

    +
    $ kubectl cluster-info
    Kubernetes master is running at https://10.114.1.100:6443
    CoreDNS is running at https://10.114.1.100:6443/api/v1/namespaces/kube-system/services/kube-dns:dns/proxy
    kubernetes-dashboard is running at https://10.114.1.100:6443/api/v1/namespaces/kube-system/services/https:kubernetes-dashboard:/proxy
    Metrics-server is running at https://10.114.1.100:6443/api/v1/namespaces/kube-system/services/https:metrics-server:/proxy

    + +
  • +
+

curl 访问

    +
  • 在 pod 里面访问

    +
    $ TOKEN=$(cat /run/secrets/kubernetes.io/serviceaccount/token)
    $ CACERT=/run/secrets/kubernetes.io/serviceaccount/ca.crt
    $ curl --cacert $CACERT --header "Authorization: Bearer $TOKEN" https://$KUBERNETES_SERVICE_HOST:$KUBERNETES_SERVICE_PORT/api
    {
    "kind": "APIVersions",
    "versions": [
    "v1"
    ],
    "serverAddressByClientCIDRs": [
    {
    "clientCIDR": "0.0.0.0/0",
    "serverAddress": "10.114.1.110:6443"(另外一个master节点ip)
    }
    ]
    }
    +
  • +
  • 在 master 节点上访问

    +
    $ APISERVER=$(kubectl config view | grep server | cut -f 2- -d ":" | tr -d " ")
    $ TOKEN=$(kubectl describe secret $(kubectl get secrets | grep default | cut -f1 -d ' ') | grep -E '^token'| cut -f2 -d':'| tr -d '\t')
    $ curl $APISERVER/api --header "Authorization: Bearer $TOKEN" --insecure
    {
    "kind": "Status",
    "apiVersion": "v1",
    "metadata": {

    },
    "status": "Failure",
    "message": "Unauthorized",
    "reason": "Unauthorized",
    "code": 401
    }
    +

    参考

  • +
  • kube-apiserver

    +
  • +
  • kubernetes 组件

    +
  • +
+]]>
+ + Kubernetes + + + k8s + api-server + +
+ + [Kubernetes] Kubernetes 中的弹性伸缩以及自动扩容 + /blog/2021/01/24/Kubernetes-Kubernetes-%E4%B8%AD%E7%9A%84%E5%BC%B9%E6%80%A7%E4%BC%B8%E7%BC%A9%E4%BB%A5%E5%8F%8A%E8%87%AA%E5%8A%A8%E6%89%A9%E5%AE%B9/ + + + Kubernetes + + + k8s + 弹性伸缩 + 自动扩容 + + + + 2020 年终总结 + /blog/2021/01/12/2020-%E5%B9%B4%E7%BB%88%E6%80%BB%E7%BB%93/ + 一直以来自己是不喜欢将一些总结放到博客里来的,感觉这个还是挺私密的,是自己一年的发展回顾。但是看了很多大佬的博客,他们都很擅于总结自己的一年,并且也会将之发到自己的博客上,我感觉这样也挺好的。自己之前都是将这些总结放到本地存储,但这样有时写了一会就不想去写了,很容易虎头蛇尾。因此我决定以后可以将一些总结,感触什么的放到博客里,以此来监督自己一直坚持下去~

+ + +

2020,一个不平凡的一年,这整年人人都基本是带着口罩过来的,直到现在还是无法摆脱带口罩,每天出行仍需带着上地铁,进公司。在年初,因为疫情影响,相信很多人都是被困在家远程办公。刚开始在家办公,自己还是不适应的,没有公司的那种开发氛围,很多需求也不能面对面及时的沟通得以解决,这样还是挺不方便的。但是后来,随着在家办公的时间长了,感觉在家办公也不错,至少节省了上下班通勤路上的时间,每天从床上爬起来就可以投入工作,这种感觉还是挺好的。当然这样对于大多数人工作效率肯定是很低的,所以公司还是会尽量要求员工在家隔离完就需要回公司办公了,因此自己大概在今年3月份回到联想大厦办公了。

+

其实自己在年初的时候给自己的2020定了一些计划的,但是关于实现与否,还真是偏差甚远。首先是打算这一年换一份工作的,最好是NLP算法工程师相关的工作。在今年的前三个月里,自己还是很认真的在学习NLP相关的知识,但是后面发现自己还是很难去找这相关的工作,加上后面在联想又大部分时间在做开发相关的工作,所以后面也就没再学习了。关于跳槽,从今年8月份开始更新几个网站的简历,然后也是8月份开始陆续接到了很多猎头的电话,也面试了很多了公司,最终拿了几个offer,待遇什么的较联想这边也有一定的涨幅。最后选择了一家互联网+金融的公司,信也科技,但不是算法相关的岗位,不过也挺符合自己的发展方向的,目前主要是机器学习容器云平台开发,主要是
Python / Go 作为技术栈, 基于 Kubernetes / Docker 打造基于云原生上传数据集,标注,特征提取,训练以及模型部署一体化的机器学习平台。

+]]>
+
+ + [GO] — 解析 GOROOT、GOPATH 以及 ubuntu 中构建 golang 项目 + /blog/2020/12/27/GO-%E2%80%94-%E8%A7%A3%E6%9E%90-GOROOT%E3%80%81GOPATH-%E4%BB%A5%E5%8F%8A-UBUNTU-%E4%B8%AD%E6%9E%84%E5%BB%BA-golang-%E9%A1%B9%E7%9B%AE/ + + + GO + + + gopath + go-modules + + + + [GO] golang学习之interface接口 + /blog/2020/12/26/GO-%E2%80%94-Golang%E5%AD%A6%E4%B9%A0%E4%B9%8Binterface%E6%8E%A5%E5%8F%A3/ + + + GO + + + interface + + + + [Kubernetes] 认识一下Kubernetes + /blog/2020/10/29/Kubernetes-%E8%AE%A4%E8%AF%86%E4%B8%80%E4%B8%8BKubernetes/ + 有哪些组件

Kubernetes 集群分为两个部分:

+
    +
  • Kubernetes 控制平面
  • +
  • (工作)节点
  • +
+

其中控制平面的组件有:

+
    +
  • Etcd 分布式持久化存储
  • +
  • API Server
  • +
  • Kube Scheduler
  • +
  • Kube Controller
  • +
+

运行容器任务依赖于每个工作节点上运行的组件,包括:

+
    +
  • Kubelet
  • +
  • Kubelet 服务代理(kube proxy)
  • +
  • 容器运行时(docker,rkt,containerd或者其他)
  • +
+ +
class Solution:
# 返回[a,b] 其中ab是出现一次的两个数字
def FindNumsAppearOnce(self, array):
# write code here
if array is None:
return

hash_map = {}
for num in array:
if num in hash_map:
hash_map[num] += 1
else:
hash_map[num] = 1

res = [num for num in hash_map.keys() if hash_map[num] == 1]
return res
+

代码测试:

+
if __name__ == "__main__":
print(Solution().FindNumsAppearOnce([2, 3, 1, 5, 1, 3, 6, 11, 6, 0, 11, 5]))

>>> [2, 0]

]]>
+ + 刷题 + + + 剑指offer + +
+ + 剑指offer 第八天 + /blog/2020/07/20/%E5%89%91%E6%8C%87offer-%E7%AC%AC%E5%85%AB%E5%A4%A9/ + JZ59 按之字形顺序打印二叉树

题目描述:

+
+

请实现一个函数按照之字形打印二叉树,即第一行按照从左到右的顺序打印,第二层按照从右至左的顺序打印,第三行按照从左到右的顺序打印,其他行以此类推。

+
+

解法思路:
这道题其实是昨天最后一道题JZ60的升级版,其实也就是层次遍历二叉树(BFS)。层次遍历思想可以参见上一道题,只是此题需要结合二叉树的深度depth进行解题。在每次需要打印的地方,当深度depth对2取余,为0则从左到右打印,为1则反转打印。

+
class TreeNode:
def __init__(self, x):
self.val = x
self.left = None
self.right = None


class Solution:
def Print(self, pRoot):
# write code here
if pRoot is None:
return []

depth = 0
node_queue = [pRoot]
res = []

while node_queue:
val = []
length = len(node_queue)
for i in range(length):
current = node_queue.pop(0)
val.append(current.val)

if current.left:
node_queue.append(current.left)

if current.right:
node_queue.append(current.right)

if depth % 2 == 0:
res.append(val)
else:
res.append(list(reversed(val)))

depth += 1

return res
+

代码测试:

+
if __name__ == "__main__":
root = TreeNode(0)
root.left = TreeNode(1)
root.right = TreeNode(2)
root.left.left = TreeNode(3)
root.left.right = TreeNode(4)
root.right.left = TreeNode(5)
root.right.left.left = TreeNode(6)

print(Solution().Print(root))

>>> [[0], [2, 1], [3, 4, 5], [6]]
+ +

JZ58 对称的二叉树

题目描述:

+
+

请实现一个函数,用来判断一棵二叉树是不是对称的。注意,如果一个二叉树同此二叉树的镜像是同样的,定义其为对称的。

+
+

解法思路:

+ +
class TreeNode:
def __init__(self, x):
self.val = x
self.left = None
self.right = None


class Solution:
def isSymmetrical(self, pRoot):
# write code here
pass
+

代码测试:

+
if __name__ == "__main__":
num = 1
matrix = [[0 for i in range(4)] for j in range(4)]
for i in range(4):
for j in range(4):
matrix[i][j] = num
num += 1

print(Solution().printMatrix(matrix))
print(Solution().printMatrix([[1, 2], [3, 4], [5, 6], [7, 8], [9, 10]]))

>>> [1, 2, 3, 4, 8, 12, 16, 15, 14, 13, 9, 5, 6, 7, 11, 10]
[1, 2, 4, 6, 8, 10, 9, 7, 5, 3]


+ +

JZ38 二叉树的下一个结点

题目描述:

+
+

给定一个二叉树和其中的一个结点,请找出中序遍历顺序的下一个结点并且返回。注意,树中的结点不仅包含左右子结点,同时包含指向父结点的指针。

+
+

解法思路:

+
class TreeNode:
def __init__(self, x):
self.val = x
self.left = None
self.right = None


class Solution:
def GetNext(self, pNode):
# write code here
pass
+

代码测试:

+
if __name__ == "__main__":
root = TreeNode(0)
root.left = TreeNode(1)
root.right = TreeNode(2)
root.left.left = TreeNode(3)
root.left.right = TreeNode(4)
root.right.left = TreeNode(5)
root.right.left.left = TreeNode(6)

print(Solution().TreeDepth(root))
print(Solution2().TreeDepth(root))

>>> 4
4
+

JZ38 平衡二叉树

题目描述:

+
+

输入一棵二叉树,判断该二叉树是否是平衡二叉树。

+
+
+

在这里,我们只需要考虑其平衡性,不需要考虑其是不是排序二叉树

+
+

解法思路:

+
class TreeNode:
def __init__(self, x):
self.val = x
self.left = None
self.right = None


class Solution:
def IsBalanced_Solution(self, pRoot):
# write code here
pass

+ +

代码测试:

+
if __name__ == "__main__":
root = TreeNode(0)
root.left = TreeNode(1)
root.right = TreeNode(2)
root.left.left = TreeNode(3)
root.left.right = TreeNode(4)
root.right.left = TreeNode(5)
root.right.left.left = TreeNode(6)

print(Solution().TreeDepth(root))
print(Solution2().TreeDepth(root))

>>> 4
4
]]>
+ + 刷题 + + + 剑指offer + +
+ + 剑指offer 第七天 + /blog/2020/07/19/%E5%89%91%E6%8C%87offer-%E7%AC%AC%E4%B8%83%E5%A4%A9/ + JZ19 顺时针打印矩阵

题目描述:

+
+

输入一个矩阵,按照从外向里以顺时针的顺序依次打印出每一个数字,例如,如果输入如下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

+

看了下讨论区,发现只是需要确定几个固定位置的索引值,便可以不管输入矩阵的大小,自适应的便能够确定顺时针打印每个位置的索引,然后再根据这个索引来打印矩阵就行,还真是巧妙。其实在确定好几个顶点的位置,也就相当于确定了方向,然后不管是顺时针还是逆时针,下次都可以方便的解题了。

+ +
class Solution:
# matrix类型为二维列表,需要返回列表
def printMatrix(self, matrix):
# write code here
top = 0
bottom = len(matrix)
left = 0
right = len(matrix[0])

res = []
# 判断是否越界
while top < bottom and left < right:
# 最上面一行,需向右打印
res.extend([matrix[top][c] for c in range(left, right)])
# 最右边一行,需向下打印
res.extend([matrix[r][right - 1] for r in range(top + 1, bottom)])
# 最下面一行,需向左打印
if bottom - top > 1:
res.extend([matrix[bottom - 1][c] for c in range(right - 2, left, -1)]) # 注意需要将右边那个值去除掉
# 最左边一行,需向上打印
if right - left > 1:
res.extend([matrix[r][left] for r in range(bottom - 1, top, -1)])

top += 1
bottom -= 1
left += 1
right -= 1

return res
+

代码测试:

+
if __name__ == "__main__":
num = 1
matrix = [[0 for i in range(4)] for j in range(4)]
for i in range(4):
for j in range(4):
matrix[i][j] = num
num += 1

print(Solution().printMatrix(matrix))
print(Solution().printMatrix([[1, 2], [3, 4], [5, 6], [7, 8], [9, 10]]))

>>> [1, 2, 3, 4, 8, 12, 16, 15, 14, 13, 9, 5, 6, 7, 11, 10]
[1, 2, 4, 6, 8, 10, 9, 7, 5, 3]


+ +

JZ38 二叉树的深度

题目描述:

+
+

输入一棵二叉树,求该树的深度。从根结点到叶结点依次经过的结点(含根、叶结点)形成树的一条路径,最长路径的长度为树的深度。

+
+

解法思路:

+
class TreeNode:
def __init__(self, x):
self.val = x
self.left = None
self.right = None


class Solution:
def TreeDepth(self, pRoot):
# write code here
if not pRoot:
return 0

x = pRoot

left = self.TreeDepth(pRoot.left)
right = self.TreeDepth(pRoot.right)

return max(left, right) + 1


class Solution2:
def TreeDepth(self, pRoot):
# write code here
if pRoot is None:
return 0
q = []
depth = 0
q.append(pRoot)
while len(q): # 队列为空时说明没有下一层
length = len(q)
for i in range(length): # 遍历层的每个节点看是否有子节点有则加入
current = q.pop(0) # current为当前遍历到的层中节点,取出,注意pop(-1)为默认,这里要pop(0),取出第一个,先入先出
if current.left:
q.append(current.left)
if current.right:
q.append(current.right)
depth += 1
return depth
+

代码测试:

+
if __name__ == "__main__":
root = TreeNode(0)
root.left = TreeNode(1)
root.right = TreeNode(2)
root.left.left = TreeNode(3)
root.left.right = TreeNode(4)
root.right.left = TreeNode(5)
root.right.left.left = TreeNode(6)

print(Solution().TreeDepth(root))
print(Solution2().TreeDepth(root))

>>> 4
4
+

JZ60 把二叉树打印成多行

题目描述:

+
+

从上到下按层打印二叉树,同一层结点从左至右输出。每一层输出一行。

+
+

解法思路:

+
class TreeNode:
def __init__(self, x):
self.val = x
self.left = None
self.right = None


class Solution:
# 返回二维列表[[1,2],[4,5]]
def Print(self, pRoot):
# write code here
if not pRoot:
return []

node_queue = [pRoot]
res = []
while node_queue:
val = []
length = len(node_queue)
for i in range(length):
current = node_queue.pop(0)
val.append(current.val)

if current.left:
node_queue.append(current.left)
if current.right:
node_queue.append(current.right)

res.append(val)

return res
+

代码测试:

+
if __name__ == "__main__":
root = TreeNode(8)
root.left = TreeNode(6)
root.right = TreeNode(10)
root.left.left = TreeNode(5)
root.left.right = TreeNode(7)
root.right.left = TreeNode(9)
root.right.right = TreeNode(11)

print(Solution().Print(root))

>>> [[8], [6, 10], [5, 7, 9, 11]]
]]>
+ + 刷题 + + + 剑指offer + +
+ + 剑指offer 第六天 + /blog/2020/07/13/%E5%89%91%E6%8C%87offer-%E7%AC%AC%E5%85%AD%E5%A4%A9/ + JZ6 旋转数组的最小数字

题目描述:

+
+

把一个数组最开始的若干个元素搬到数组的末尾,我们称之为数组的旋转。
输入一个非递减排序的数组的一个旋转,输出旋转数组的最小元素。
例如数组{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指数组中间位置的数。

+
+ +
class Solution:
def minNumberInRotateArray(self, rotateArray):
# write code here
if len(rotateArray) == 0:
return 0
left = 0
right = len(rotateArray) - 1
while left < right:
if rotateArray[left] < rotateArray[right]:
return rotateArray[left]

mid = (left + right) // 2
if rotateArray[mid] > rotateArray[left]:
left = mid + 1
elif rotateArray[mid] < rotateArray[right]:
right = mid
else:
left += 1

return rotateArray[left]
+

代码测试:

+
if __name__ == "__main__":
print(Solution().minNumberInRotateArray([1, 0, 1, 1, 1]))

>>> 0

+ +

JZ18 二叉树的镜像

题目描述:

+
+

操作给定的二叉树,将其变换为源二叉树的镜像。
二叉树的镜像定义如下:

+
+
 源二叉树
+    8
+   /  \
+  6   10
+ / \  / \
+5  7 9 11
+
+镜像二叉树
+     8
+   /  \
+  10   6
+ / \  / \
+11 9 7  5

解法思路:

+
class TreeNode:
def __init__(self, x):
self.val = x
self.left = None
self.right = None


class Solution:
# 返回镜像树的根节点
def Mirror(self, root):
# write code here
if root is None:
return

root.left, root.right = \
self.Mirror(root.right), self.Mirror(root.left)

return root

def preOrder(self, root):
if root is None:
return

print(root.val, end=' ')
self.preOrder(root.left)
self.preOrder(root.right)
+

代码测试:

+
if __name__ == "__main__":
tree1 = TreeNode(8)
tree1.left = TreeNode(6)
tree1.right = TreeNode(10)
tree1.left.left = TreeNode(5)
tree1.left.right = TreeNode(7)
tree1.right.left = TreeNode(9)
tree1.right.right = TreeNode(11)

invert_tree = Solution().Mirror(tree1)
print(Solution().preOrder(invert_tree))

>>> 8 10 11 9 6 7 5 None
+

JZ23 二叉搜索树的后序遍历

题目描述:

+
+

输入一个整数数组,判断该数组是不是某二叉搜索树的后序遍历的结果。如果是则输出Yes,否则输出No。假设输入的数组的任意两个数字都互不相同。

+
+

解法思路:

+
class Solution:
def VerifySquenceOfBST(self, sequence):
# write code here
if len(sequence) == 0:
return False

root = sequence[-1]
for index, value in enumerate(sequence):
if value > root:
break

for value in sequence[index: -1]:
if value < root:
return False

left = True
if index > 0:
left = self.VerifySquenceOfBST(sequence[:index])

right = True
if index < len(sequence) - 1:
right = self.VerifySquenceOfBST(sequence[index: -1])

return left and right
+

代码测试:

+
if __name__ == "__main__":
is_binary_tree = [1, 3, 5, 9, 12, 10, 7]
print(Solution().VerifySquenceOfBST(is_binary_tree))

>>> True
+ +

JZ67 剪绳子

题目描述:

+
+

给你一根长度为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

+
+

解法思路:

+

代码测试:

+]]>
+ + 刷题 + + + 剑指offer + +
+ + 剑指offer 第五天 + /blog/2020/07/13/%E5%89%91%E6%8C%87offer-%E7%AC%AC%E4%BA%94%E5%A4%A9/ + JZ8 跳台阶

题目描述:

+
+

一只青蛙一次可以跳上1级台阶,也可以跳上2级。求该青蛙跳上一个n级的台阶总共有多少种跳法(先后次序不同算不同的结果)。

+
+

解法思路:

+ +
class Solution:
def jumpFloor(self, number):
# write code here
if number <= 2:
return number

res, counter = 1, 0
for i in range(1, number + 1):
res = res + counter
counter = res - counter

return res
+

代码测试:

+
if __name__ == "__main__":
print(Solution().jumpFloor(3))

>>> 3

+ +

JZ9 变态跳台阶

题目描述:

+
+

一只青蛙一次可以跳上1级台阶,也可以跳上2级……它也可以跳上n级。求该青蛙跳上一个n级的台阶总共有多少种跳法。

+
+

解法思路:

+
class Solution:
def jumpFloor(self, number):
# write code here
if number <= 2:
return number

curr, prev = 1, 1
for i in range(1, number):
curr = 2 * prev
prev = curr

return curr
+

代码测试:

+
if __name__ == "__main__":
print(Solution().jumpFloor(3))

>>> 4
+

JZ10 矩形覆盖

题目描述:

+
+

我们可以用21的小矩形横着或者竖着去覆盖更大的矩形。请问用n个21的小矩形无重叠地覆盖一个2*n的大矩形,总共有多少种方法?

+
+

解法思路:

+
class Solution:
def rectCover(self, number):
# write code here
if number <= 2:
return number

res, counter = 1, 0
for i in range(1, number + 1):
res = res + counter
counter = res - counter

return res
+

代码测试:

+
if __name__ == "__main__":
print(Solution().rectCover(4))

>>> 5
+ +

JZ21 栈的压入、弹出序列

题目描述:

+
+

输入两个整数序列,第一个序列表示栈的压入顺序,请判断第二个序列是否可能为该栈的弹出顺序。假设压入栈的所有数字均不相等。
例如序列1,2,3,4,5是某栈的压入顺序,序列4,5,3,2,1是该压栈序列对应的一个弹出序列,但4,3,5,1,2就不可能是该压栈序列的弹出序列。
(注意:这两个序列的长度是相等的)

+
+

解法思路:

+
class Solution:
def IsPopOrder(self, pushV, popV):
# write code here
pass
+ +

代码测试:

+]]>
+ + 刷题 + + + 剑指offer + +
+ + 剑指offer 第四天 + /blog/2020/07/11/%E5%89%91%E6%8C%87offer-%E7%AC%AC%E5%9B%9B%E5%A4%A9/ + JZ4 重建二叉树

题目描述:

+
+

输入某二叉树的前序遍历和中序遍历的结果,请重建出该二叉树。假设输入的前序遍历和中序遍历的结果中都不含重复的数字。例如输入前序遍历序列 [1,2,4,7,3,5,6,8] 和中序遍历序列 [4,7,2,1,5,3,8,6] ,则重建二叉树并返回。

+
+

解法思路:
使用递归的方法求解。这道题需要对二叉树的性质比较了解,需要熟悉二叉树的几种遍历方式。

+

前序遍历是先遍历根节点,然后遍历左节点,最后遍历右节点(根左右)

+

中序遍历是先遍历左节点,然后遍历根节点,最后遍历右节点(左根右)

+

后序遍历是先遍历左节点,然后遍历右节点,最后遍历根节点(根左右)

+

本题给定前序遍历以及中序遍历的序列,可以知道前序遍历第一个值一定是根节点。而根节点在中序遍历中会把左右子树分成两半。因此本题的关键是找到根节点,然后将左右子树依次递归重建得到二叉树。

+

使用递归是需要结束条件的,当前序或中序遍历序列为None时,便可推出递归,得到二叉树。

+ +
class TreeNode:
def __init__(self, x):
self.val = x
self.left = None
self.right = None


class Solution:
# 返回构造的TreeNode根节点
def reConstructBinaryTree(self, pre, tin):
if not pre or not tin:
return None

root = TreeNode(pre.pop(0))
index = tin.index(root.val)

root.left = self.reConstructBinaryTree(pre, tin[:index])
root.right = self.reConstructBinaryTree(pre, tin[index + 1:])

return root

def preOrder(self, root):
if root is None:
return

print(root.val, end=' ')
self.preOrder(root.left)
self.preOrder(root.right)

def InOrder(self, root):
if root is None:
return
self.InOrder(root.left)
print(root.val, end=' ')
self.InOrder(root.right)

def BackOrder(self, root):
if root is None:
return
self.BackOrder(root.left)
self.BackOrder(root.right)
print(root.val, end=' ')
+

本题只需写好reConstructBinaryTree这个方法,上面代码其他三个函数是用来前序、中序以及后序遍历重建得到二叉树的,以方便大家调试。
代码测试:

+
if __name__ == "__main__":
pre = [1, 2, 4, 7, 3, 5, 6, 8]
tin = [4, 7, 2, 1, 5, 3, 8, 6]

reTree = Solution().reConstructBinaryTree(pre, tin)
print("前序遍历:")
Solution().preOrder(reTree)
print("\n")
print("中序遍历:")
Solution().InOrder(reTree)
print("\n")
print("后序遍历:")
Solution().BackOrder(reTree)

>>> 前序遍历:
1 2 4 7 3 5 6 8

中序遍历:
4 7 2 1 5 3 8 6

后序遍历:
7 4 2 5 8 6 3 1

+ +

JZ18 二叉树的镜像

题目描述:

+
+

操作给定的二叉树,将其变换为源二叉树的镜像。
二叉树的镜像定义如下:

+
+
 源二叉树
+    8
+   /  \
+  6   10
+ / \  / \
+5  7 9 11
+
+镜像二叉树
+     8
+   /  \
+  10   6
+ / \  / \
+11 9 7  5

解法思路:

+
class TreeNode:
def __init__(self, x):
self.val = x
self.left = None
self.right = None


class Solution:
# 返回镜像树的根节点
def Mirror(self, root):
# write code here
if root is None:
return

root.left, root.right = \
self.Mirror(root.right), self.Mirror(root.left)

return root

def preOrder(self, root):
if root is None:
return

print(root.val, end=' ')
self.preOrder(root.left)
self.preOrder(root.right)
+

代码测试:

+
if __name__ == "__main__":
tree1 = TreeNode(8)
tree1.left = TreeNode(6)
tree1.right = TreeNode(10)
tree1.left.left = TreeNode(5)
tree1.left.right = TreeNode(7)
tree1.right.left = TreeNode(9)
tree1.right.right = TreeNode(11)

invert_tree = Solution().Mirror(tree1)
print(Solution().preOrder(invert_tree))

>>> 8 10 11 9 6 7 5 None
+

JZ23 二叉搜索树的后序遍历

题目描述:

+
+

输入一个整数数组,判断该数组是不是某二叉搜索树的后序遍历的结果。如果是则输出Yes,否则输出No。假设输入的数组的任意两个数字都互不相同。

+
+

解法思路:

+
class Solution:
def VerifySquenceOfBST(self, sequence):
# write code here
if len(sequence) == 0:
return False

root = sequence[-1]
for index, value in enumerate(sequence):
if value > root:
break

for value in sequence[index: -1]:
if value < root:
return False

left = True
if index > 0:
left = self.VerifySquenceOfBST(sequence[:index])

right = True
if index < len(sequence) - 1:
right = self.VerifySquenceOfBST(sequence[index: -1])

return left and right
+

代码测试:

+
if __name__ == "__main__":
is_binary_tree = [1, 3, 5, 9, 12, 10, 7]
print(Solution().VerifySquenceOfBST(is_binary_tree))

>>> True
+ +

JZ67 剪绳子

题目描述:

+
+

给你一根长度为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

+
+

解法思路:

+

代码测试:

+]]>
+ + 刷题 + + + 剑指offer + +
+ + 剑指offer 第三天 + /blog/2020/07/08/%E5%89%91%E6%8C%87offer-%E7%AC%AC%E4%B8%89%E5%A4%A9/ + JZ11 二进制中1的个数

题目描述:

+
+

输入一个整数,输出该数32位二进制表示中1的个数。其中负数用补码表示。

+
+

解法思路:

+ +
def NumberOf1(self, n):
# write code here
count = 0

if n < 0:
n = n & 0b11111111111111111111111111111111

while n != 0:
count += 1
n = n & (n - 1)

return count
+

代码测试:

+
if __name__ == "__main__":
print(Solution().NumberOf1(-11))

>>> 30
+ +

JZ27 字符串的排列

题目描述:

+
+

输入一个字符串,按字典序打印出该字符串中字符的所有排列。例如输入字符串abc,则打印出由字符a,b,c所能排列出来的所有字符串abc,acb,bac,bca,cab和cba。

+
+
+

输入一个字符串,长度不超过9(可能有字符重复),字符只包括大小写字母。

+
+

解法思路:

+
class Solution:
def Permutation(self, ss):
# write code here
pass
+ +

代码测试:

+

+

JZ47 求1 + 2 + 3 + … + n

题目描述:

+
+

求1+2+3+…+n,要求不能使用乘除法、for、while、if、else、switch、case等关键字及条件判断语句(A?B:C)。

+
+

解法思路:

+
class Solution:
def Sum_Solution(self, n):
# write code here
res = n
try:
res % n
res += self.Sum_Solution(n - 1)
except ZeroDivisionError:
return 0

return res


class Solution2:
def Sum_Solution(self, n):
# write code here
res = n
tmp = (res and self.Sum_Solution(n - 1))
res += tmp

return res
+

代码测试:

+
if __name__ == "__main__":
print(Solution().Sum_Solution(5))
print(Solution2().Sum_Solution(6))

>>> 15
21
+ +

JZ51 构建乘积数组

题目描述:

+
+

给定一个数组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];)

+
+

解法思路:

+
class Solution:
def multiply(self, A):
# write code here
pass
+ +

代码测试:

+]]>
+ + 刷题 + + + 剑指offer + +
+ + 剑指offer 第二天 + /blog/2020/07/07/%E5%89%91%E6%8C%87offer%E7%AC%AC%E4%BA%8C%E5%A4%A9/ + JZ49 把字符串转化成整数

题目描述:

+
+

将一个字符串转换成一个整数,要求不能使用字符串转换整数的库函数。 数值为0或者字符串不是一个合法的数值则返回0
输入描述:
输入一个字符串,包括数字字母符号,可以为空
输出描述:
如果是合法的数值表达则返回该数字,否则返回0

+
+
+

示例:
输入:
+2147483647
1a33
输出:
2147483647
0

+
+

解法思路:
使用了一个很巧妙的方法,用一个字典将字符串”0”-“9”与数字0 - 9做一个映射,然后再用数学上计算一个数字的公式得出这个数。比如:123 = (1 * 10 + 2 ) * 10 + 3。需要注意字符串开头的正负号,从而判断得到的数字是整数还是负数。

+ +
class Solution:
def StrToInt(self, s):
# write code here
if len(s) == 0:
return 0

str2num = {
"0": 0, "1": 1, "2": 2, "3": 3, "4": 4,
"5": 5, "6": 6, "7": 7, "8": 8, "9": 9,
"+": 1, "-": -1
}

sum = 0
sign = 1
for c in s:
if c in str2num:
if c == "+":
sign = str2num["+"]
continue
if c == "-":
sign = str2num["-"]
continue
sum = sum * 10 + str2num[c]
else:
sum = 0
break

return sum * sign
+

代码测试:

+
if __name__ == "__main__":
s = "-98210"
print(Solution().StrToInt(s))

>>> 98210
+ +

JZ7 斐波那契数列

题目描述:

+
+

大家都知道斐波那契数列,现在要求输入一个整数n,请你输出斐波那契数列的第n项(从0开始,第0项为0,第1项是1)(n<=39)。

+
+

解法一思路:
直接根据数学公式f(n) = f(n - 1) + f(n - 2),截至条件是当n = 1, f(n) = 1n = 0, f(0) = 0。利用递归法进行求解,这种方法时间复杂度很大,为O(n^2),空间复杂度为O(1)

+
class Solution:
def Fibonacci(self, n):
# write code here
if n <= 1:
return n
else:
return self.Fibonacci(n-1) + self.Fibonacci(n-2)
+ +

解法二思路:

+
class Solution2:
def Fibonacci(self, n):
# write code here
if n <= 1:
return n

n1, n2, n3 = 0, 1, 0
for i in range(1, n):
n3 = n1 + n2
n1 = n2
n2 = n3

return n3
+

解法三思路:

+
class Solution3:
def Fibonacci(self, n):
# write code here
if n <= 1:
return n

sum, one = 1, 0
for i in range(1, n):
sum = sum + one
one = sum - one

return sum
+ +

代码测试:

+
if __name__ == "__main__":
print(Solution().Fibonacci(8))
print(Solution2().Fibonacci(8))
print(Solution3().Fibonacci(8))

>>> 21
>>> 21
>>> 21
+

JZ48 不用加减乘除做加法

题目描述:

+
+

写一个函数,求两个整数之和,要求在函数体内不得使用+、-、*、/四则运算符号。

+
+

解法思路:

+
class Solution:
def Add(self, num1, num2):
# write code here
pass
+

代码测试:

+

]]>
+ + 刷题 + + + 剑指offer + +
+ + 剑指offer 第一天 + /blog/2020/07/06/%E5%89%91%E6%8C%87offer-%E7%AC%AC%E4%B8%80%E5%A4%A9/ + JZ16 合并两个排序的链表

题目描述:

+
+

输入两个单调递增的链表,输出两个链表合成后的链表,当然我们需要合成后的链表满足单调不减规则。

+
+

解法一思路:
使用迭代的方法。先判断临界情况,依次判断输入的两个链表是否为空指针,如果有其中一个为空指针链表,则返回另一个有序的链表。

+

然后初始化一个新链表,依次比较两个有序链表的值,哪个链表的值较小,则新链表的指针指向该值。继续循环,依次比较,最终返回单调递增的新链表。

+
class ListNode:
def __init__(self, x):
self.val = x
self.next = None


class Solution2:
# 返回合并后列表
def Merge(self, pHead1, pHead2):
# write code here
if pHead1 is None:
return pHead2
if pHead2 is None:
return pHead1

node = sorted_node = ListNode(0)

while pHead1 and pHead2:
if pHead1.val < pHead2.val:
node.next = pHead1
pHead1 = pHead1.next
else:
node.next = pHead2
pHead2 = pHead2.next
node = node.next

if pHead1 or pHead2:
node.next = pHead1 or pHead2

return sorted_node.next

def travel_list(self, node):
while node is not None:
print(node.val, end=" ")
node = node.next
+

解法二思路:
使用递归的方法。大体思路同上,先判断临界情况,依次判断输入的两个链表是否为空指针,如果有其中一个为空指针链表,则返回另一个有序的链表。

+

然后依次比较两个有序链表的值,哪个链表的值较小,则将该节点赋值给新链表。使用递归,直至其中一个链表为None,最终返回和并得到的单调递增链表。

+ +
class ListNode:
def __init__(self, x):
self.val = x
self.next = None

class Solution:
# 返回合并后列表
def Merge(self, pHead1, pHead2):
# write code here
if pHead1 is None:
return pHead2
if pHead2 is None:
return pHead1

if pHead1.val < pHead2.val:
sorted_list = pHead1
sorted_list.next = self.Merge(pHead1.next, pHead2)
else:
sorted_list = pHead2
sorted_list.next = self.Merge(pHead1, pHead2.next)

return sorted_list

def travel_list(self, node):
while node is not None:
print(node.val, end=" ")
node = node.next
+

代码测试:

+
if __name__ == "__main__":
node_1 = ListNode(0)
node_1.next = ListNode(4)
node_1.next.next = ListNode(10)
node_2 = ListNode(2)
node_2.next = ListNode(3)
node_2.next.next = ListNode(12)
solu_1 = Solution()
# print(solu_1.travel_list(solu_1.Merge(node_1, node_2)))
solu_2 = Solution2()
print(solu_2.travel_list(solu_2.Merge(node_1, node_2)))

>>> 0 2 3 4 10 12 None
+ +

JZ14 链表中倒数第k个结点

题目描述:

+
+

输入一个链表,输出该链表中倒数第k个结点。

+
+

解法一思路:

+
lass ListNode:
def __init__(self, x):
self.val = x
self.next = None


class Solution:
# 时间复杂度: O(n)
# 空间复杂度: O(n)
def FindKthToTail(self, head, k):
# write code here
res = []

while head is not None:
res.insert(0, head.val)
head = head.next

if len(res) < k or k < 1:
return

return res[k-1]

def travel_listNode(self, listNode):
while listNode:
print(listNode.val, end=" ")
listNode = listNode.next
+ +

解法二思路:

+
class Solution2:
# 时间复杂度: O(n)
# 空间复杂度: O(1)
def FindKthToTail(self, head, k):
# write code here
if k < 0 or head is None:
return

slow, fast = head, head
count = 0
while fast.next is not None:
fast = fast.next
if count >= k - 1:
slow = slow.next
count += 1

if count >= k - 1:
return slow.val

return None
+

代码测试:

+
if __name__ == "__main__":
curr = head = ListNode(0)
head.next = ListNode(1)
head = head.next
head.next = ListNode(2)
head = head.next
head.next = ListNode(3)
head = head.next
head.next = ListNode(4)

print(Solution().travel_listNode(curr))
print(Solution().FindKthToTail(curr, 5))
print(Solution2().FindKthToTail(curr, 5))

>>> 0 1 2 3 4 None
>>> 0
>>> 0
+

JZ15 反转链表

题目描述:

+
+

输入一个链表,反转链表后,输出新链表的表头。

+
+

解法思路:

+
class ListNode:
def __init__(self, x):
self.val = x
self.next = None


class Solution:
# 返回ListNode
def ReverseList(self, pHead):
# write code here
if not pHead or pHead.next is None:
return pHead

curr, prev = pHead, None
while curr:
tmp = curr.next
curr.next = prev
prev = curr
curr = tmp

return prev
+

代码测试:

+
if __name__ == "__main__":
curr = head = ListNode(0)
head.next = ListNode(1)
head = head.next
head.next = ListNode(2)
head = head.next
head.next = ListNode(3)
head = head.next
# print(head)
print(curr)

res = Solution().ReverseList(curr)
print(res)
+ +

JZ13 从尾到头打印链表

题目描述:

+
+

输入一个链表,按链表从尾到头的顺序返回一个ArrayList。

+
+

解法思路:

+
class ListNode:
def __init__(self, x):
self.val = x
self.next = None


class Solution:
# 返回从尾部到头部的列表值序列,例如[1,2,3]
def printListFromTailToHead(self, listNode):
# write code here
res = []
while listNode:
res.insert(0, listNode.val)
listNode = listNode.next

return res

def travel_listNode(self, listNode):
while listNode:
print(listNode.val, end=" ")
listNode = listNode.next
+

代码测试:

+
if __name__ == "__main__":
curr = head = ListNode(0)
head.next = ListNode(1)
head = head.next
head.next = ListNode(2)
head = head.next
head.next = ListNode(3)
head = head.next
head.next = ListNode(4)

print(Solution().travel_listNode(curr))
print(Solution().printListFromTailToHead(curr))
]]>
+ + 刷题 + + + 剑指offer + +
+ + NLP(1)文本分类知识梳理 + /blog/2020/06/27/NLP%EF%BC%881%EF%BC%89%E6%96%87%E6%9C%AC%E5%88%86%E7%B1%BB%E7%9F%A5%E8%AF%86%E6%A2%B3%E7%90%86/ + + + NLP + 文本分类 + + + 文本分类 + + + + Python之函数式编程模块(2) + /blog/2020/06/19/Python%E4%B9%8B%E5%87%BD%E6%95%B0%E5%BC%8F%E7%BC%96%E7%A8%8B%E6%A8%A1%E5%9D%97%EF%BC%882%EF%BC%89/ + 这篇文章主要是讲解一些函数式编程常用的模块,比如:itertools, functools以及operator

+

一、itertools –用以创建迭代器的模块

+ +

二、functools – 高阶函数可调用对象上的操作

三、operator – 标准运算符替代函数

在函数式编程中,我们经常需要把算术运算符当作函数使用,因此可以借助operator模块。operator 模块提供了一套与Python的内置运算符对应的高效率函数。例如,operator.add(x, y) 与表达式 x+y 相同。

+

operator 模块为多个算术运算符提供了对应的函数,从而避免编写
lambda a, b: a * b 这种平凡的匿名函数。这两种做法具体如下:

+
    +
  • 使用lambda a, b: a * b匿名函数来计算阶乘:
  • +
+
>>> from functools import reduce
>>> from operator import mul
>>> def fact(n):
... return reduce(mul, range(1, n+1))
...
>>> fact(5)
120

+
    +
  • 使用operator.mul函数来计算阶乘:
  • +
+
>>> from functools import reduce
>>> from operator import mul
>>> def fact(n):
... return reduce(mul, range(1, n+1))
...
>>> fact(5)
120

+ +

operator 模块中还有一类函数,能替代从系列中取出元素或读取对象属性的lambda表达式:

+]]>
+ + Python + + + 函数式编程 + 高级语法 + +
+ + Python之函数式编程模块(1) + /blog/2020/06/19/Python%E4%B9%8B%E5%87%BD%E6%95%B0%E5%BC%8F%E7%BC%96%E7%A8%8B%E6%A8%A1%E5%9D%97/ + 一、编程方式介绍

一般编程语言支持通过以下几种方式来解决具体的问题:

+
    +
  • 大多数的编程语言都是过程式的,也就是我们常说的面向过程的编程方式。而所谓程序是指令的列表,告诉计算机如何处理程序的输入。C、Pascal甚至Unix shell都是过程式语言。
  • +
  • 然后有一些编程语言是声明式的,主要是你需要编写一个用来描述待解决问题的说明,然后这个语言的具体实现会指明怎样高效的进行计算并解决问题。SQL 可能是你最熟悉的声明式语言了。 一个 SQL 查询语句描述了你想要检索的数据集,并且 SQL 引擎会决定是扫描整张表还是使用索引,应该先执行哪些子句等等。
  • +
  • 面向对象编程语言会操作一组对象。其中对象拥有内部状态,并能够以某种方式支持请求和修改这个内部状态的方法。Smalltalk 和 Java 都是面向对象的语言。C++ 和 Python 支持面向对象编程,但并不强制使用面向对象特性。
  • +
  • 函数式编程则是将一个问题分解成一系列函数。理想情况下,函数只接受输入并产生输出,没有任何内部状态会影响为给定输入产生的输出。众所周知的函数式语言包括ML家族(标准ML、OCaml和其他变体)和Haskell。
  • +
+ + +

一般语言设计者在设计语言时,会选择侧重强调一种特定的编程方式,但这会让以不同方式来编写程序变得困难。因此有些语言就被设计成多范式语言,用以支持以上几种不同的编程方式。其中Lisp,C++ 和 Python 都是多范式语言;使用这些语言,你可以编写主要为过程式,面向对象或者函数式的程序和函数库。在大型程序中,不同的部分可能会采用不同的方式编写;比如 GUI 可能是面向对象的而处理逻辑则是过程式或者函数式。

+

这篇文章主要是来讲解函数式编程,因此接下来主要围绕函数式编程进行展开。

+

二、函数式编程

2.1 定义

函数式编程:即为给定输入,输入会流经一系列函数,每个函数接收输入并输出结果。并且这个过程,在每个函数内部并不会修改全局变量或者有其他副作用。函数式编程允许把函数本身作为参数传入另一个函数,还允许返回一个函数。

+

2.2 特点

函数式风格有其理论和实践上的优点:

+
    +
  • 形式证明
  • +
  • 模块化
  • +
  • 组合性
  • +
  • 易于调试和测试
  • +
+

三、函数式编程实践

3.1

]]>
+ + Python + + + 函数式编程 + 高级语法 + +
+ + My first post + /blog/2020/06/18/My-first-post/ + + +
diff --git a/tags/DL/index.html b/tags/DL/index.html new file mode 100644 index 0000000..61bf2c9 --- /dev/null +++ b/tags/DL/index.html @@ -0,0 +1,442 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 标签 - DL - LuckyCrise + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ + + + + + +
+ +
+ +
+ +
+
+ +
+
+
+ + +
+

共计 1 篇文章

+
+ + + + +

2020

+ + + +
分布式训练之PyTorch
+
+ +
+ + + + + +
+
+
+
+
+ + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git "a/tags/HTTP-\351\203\250\347\275\262/index.html" "b/tags/HTTP-\351\203\250\347\275\262/index.html" new file mode 100644 index 0000000..e98e270 --- /dev/null +++ "b/tags/HTTP-\351\203\250\347\275\262/index.html" @@ -0,0 +1,442 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 标签 - HTTP 部署 - LuckyCrise + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ + + + + + +
+ +
+ +
+ +
+
+ +
+
+
+ + + + + + + + +
+
+
+
+
+ + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tags/PGN/index.html b/tags/PGN/index.html new file mode 100644 index 0000000..cbcc015 --- /dev/null +++ b/tags/PGN/index.html @@ -0,0 +1,442 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 标签 - PGN - LuckyCrise + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ + + + + + +
+ +
+ +
+ +
+
+ +
+
+
+ + +
+

共计 1 篇文章

+
+ + + + +

2020

+ + + +
[NLP] 文本摘要之PGN指针生成网络
+
+ +
+ + + + + +
+
+
+
+
+ + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tags/TF-Serving/index.html b/tags/TF-Serving/index.html new file mode 100644 index 0000000..1a842a5 --- /dev/null +++ b/tags/TF-Serving/index.html @@ -0,0 +1,442 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 标签 - TF Serving - LuckyCrise + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ + + + + + +
+ +
+ +
+ +
+
+ +
+
+
+ + + + + + + + +
+
+
+
+
+ + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tags/api-server/index.html b/tags/api-server/index.html new file mode 100644 index 0000000..57ed2d2 --- /dev/null +++ b/tags/api-server/index.html @@ -0,0 +1,442 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 标签 - api-server - LuckyCrise + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ + + + + + +
+ +
+ +
+ +
+
+ +
+
+
+ + + + + + + + +
+
+
+
+
+ + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tags/go-modules/index.html b/tags/go-modules/index.html new file mode 100644 index 0000000..74a6f1a --- /dev/null +++ b/tags/go-modules/index.html @@ -0,0 +1,442 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 标签 - go-modules - LuckyCrise + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ + + + + + +
+ +
+ +
+ +
+
+ +
+
+
+ + + + + + + + +
+
+
+
+
+ + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tags/golang/index.html b/tags/golang/index.html new file mode 100644 index 0000000..aacb4db --- /dev/null +++ b/tags/golang/index.html @@ -0,0 +1,442 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 标签 - golang - LuckyCrise + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ + + + + + +
+ +
+ +
+ +
+
+ +
+
+
+ + +
+

共计 1 篇文章

+
+ + + + +

2023

+ + + +
[GO] golang中优雅设置参数默认值
+
+ +
+ + + + + +
+
+
+
+
+ + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tags/gopath/index.html b/tags/gopath/index.html new file mode 100644 index 0000000..671c729 --- /dev/null +++ b/tags/gopath/index.html @@ -0,0 +1,442 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 标签 - gopath - LuckyCrise + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ + + + + + +
+ +
+ +
+ +
+
+ +
+
+
+ + + + + + + + +
+
+
+
+
+ + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tags/index.html b/tags/index.html new file mode 100644 index 0000000..85b9763 --- /dev/null +++ b/tags/index.html @@ -0,0 +1,426 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 标签 - LuckyCrise + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ + + + + + +
+ +
+ +
+ + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tags/interface/index.html b/tags/interface/index.html new file mode 100644 index 0000000..13bc59d --- /dev/null +++ b/tags/interface/index.html @@ -0,0 +1,442 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 标签 - interface - LuckyCrise + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ + + + + + +
+ +
+ +
+ +
+
+ +
+
+
+ + +
+

共计 1 篇文章

+
+ + + + +

2020

+ + + +
[GO] golang学习之interface接口
+
+ +
+ + + + + +
+
+
+
+
+ + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tags/k8s/index.html b/tags/k8s/index.html new file mode 100644 index 0000000..1ba2670 --- /dev/null +++ b/tags/k8s/index.html @@ -0,0 +1,463 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 标签 - k8s - LuckyCrise + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ + + + + + +
+ +
+ +
+ + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tags/kubeadm/index.html b/tags/kubeadm/index.html new file mode 100644 index 0000000..03485f0 --- /dev/null +++ b/tags/kubeadm/index.html @@ -0,0 +1,442 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 标签 - kubeadm - LuckyCrise + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ + + + + + +
+ +
+ +
+ +
+
+ +
+
+
+ + + + + + + + +
+
+
+
+
+ + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git "a/tags/\345\207\275\346\225\260\345\274\217\347\274\226\347\250\213/index.html" "b/tags/\345\207\275\346\225\260\345\274\217\347\274\226\347\250\213/index.html" new file mode 100644 index 0000000..ddc985c --- /dev/null +++ "b/tags/\345\207\275\346\225\260\345\274\217\347\274\226\347\250\213/index.html" @@ -0,0 +1,448 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 标签 - 函数式编程 - LuckyCrise + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ + + + + + +
+ +
+ +
+ +
+
+ +
+
+
+ + + + + + + + +
+
+
+
+
+ + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git "a/tags/\345\210\206\345\270\203\345\274\217\350\256\255\347\273\203/index.html" "b/tags/\345\210\206\345\270\203\345\274\217\350\256\255\347\273\203/index.html" new file mode 100644 index 0000000..6a491d7 --- /dev/null +++ "b/tags/\345\210\206\345\270\203\345\274\217\350\256\255\347\273\203/index.html" @@ -0,0 +1,442 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 标签 - 分布式训练 - LuckyCrise + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ + + + + + +
+ +
+ +
+ +
+
+ +
+
+
+ + +
+

共计 1 篇文章

+
+ + + + +

2020

+ + + +
分布式训练之PyTorch
+
+ +
+ + + + + +
+
+
+
+
+ + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git "a/tags/\345\211\221\346\214\207offer/index.html" "b/tags/\345\211\221\346\214\207offer/index.html" new file mode 100644 index 0000000..0592133 --- /dev/null +++ "b/tags/\345\211\221\346\214\207offer/index.html" @@ -0,0 +1,502 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 标签 - 剑指offer - LuckyCrise + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ + + + + + +
+ +
+ +
+ + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git "a/tags/\345\211\221\346\214\207offer/page/2/index.html" "b/tags/\345\211\221\346\214\207offer/page/2/index.html" new file mode 100644 index 0000000..c5bc00f --- /dev/null +++ "b/tags/\345\211\221\346\214\207offer/page/2/index.html" @@ -0,0 +1,448 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 标签 - 剑指offer - LuckyCrise + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ + + + + + +
+ +
+ +
+ +
+
+ +
+
+
+ + +
+

共计 11 篇文章

+
+ + + + +

2020

+ + + +
剑指offer 第一天
+
+ +
+ + + + + + + +
+
+
+
+
+ + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git "a/tags/\345\274\271\346\200\247\344\274\270\347\274\251/index.html" "b/tags/\345\274\271\346\200\247\344\274\270\347\274\251/index.html" new file mode 100644 index 0000000..500edfc --- /dev/null +++ "b/tags/\345\274\271\346\200\247\344\274\270\347\274\251/index.html" @@ -0,0 +1,442 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 标签 - 弹性伸缩 - LuckyCrise + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ + + + + + +
+ +
+ +
+ +
+
+ +
+
+
+ + + + + + + + +
+
+
+
+
+ + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git "a/tags/\346\226\207\346\234\254\345\210\206\347\261\273/index.html" "b/tags/\346\226\207\346\234\254\345\210\206\347\261\273/index.html" new file mode 100644 index 0000000..3252849 --- /dev/null +++ "b/tags/\346\226\207\346\234\254\345\210\206\347\261\273/index.html" @@ -0,0 +1,442 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 标签 - 文本分类 - LuckyCrise + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ + + + + + +
+ +
+ +
+ +
+
+ +
+
+
+ + +
+

共计 1 篇文章

+
+ + + + +

2020

+ + + +
NLP(1)文本分类知识梳理
+
+ +
+ + + + + +
+
+
+
+
+ + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git "a/tags/\346\240\221/index.html" "b/tags/\346\240\221/index.html" new file mode 100644 index 0000000..d6ba9b0 --- /dev/null +++ "b/tags/\346\240\221/index.html" @@ -0,0 +1,442 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 标签 - 树 - LuckyCrise + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ + + + + + +
+ +
+ +
+ +
+
+ +
+
+
+ + +
+

共计 1 篇文章

+
+ + + + +

2020

+ + + +
[LeetCode] 数据结构之树
+
+ +
+ + + + + +
+
+
+
+
+ + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git "a/tags/\350\207\252\345\212\250\346\211\251\345\256\271/index.html" "b/tags/\350\207\252\345\212\250\346\211\251\345\256\271/index.html" new file mode 100644 index 0000000..9152580 --- /dev/null +++ "b/tags/\350\207\252\345\212\250\346\211\251\345\256\271/index.html" @@ -0,0 +1,442 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 标签 - 自动扩容 - LuckyCrise + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ + + + + + +
+ +
+ +
+ +
+
+ +
+
+
+ + + + + + + + +
+
+
+
+
+ + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git "a/tags/\351\253\230\347\272\247\350\257\255\346\263\225/index.html" "b/tags/\351\253\230\347\272\247\350\257\255\346\263\225/index.html" new file mode 100644 index 0000000..d8f6e08 --- /dev/null +++ "b/tags/\351\253\230\347\272\247\350\257\255\346\263\225/index.html" @@ -0,0 +1,448 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 标签 - 高级语法 - LuckyCrise + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ + + + + + +
+ +
+ +
+ +
+
+ +
+
+
+ + + + + + + + +
+
+
+
+
+ + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/xml/local-search.xml b/xml/local-search.xml new file mode 100644 index 0000000..d7d0c01 --- /dev/null +++ b/xml/local-search.xml @@ -0,0 +1,45 @@ + + + {% if posts %} + {% for post in posts.toArray() %} + {% if post.indexing == undefined or post.indexing %} + + {{ post.title }} + + {{ [url, post.path] | urlJoin | uriencode }} + {% if content %} + + {% endif %} + {% if post.categories and post.categories.length>0 %} + + {% for cate in post.categories.toArray() %} + {{ cate.name }} + {% endfor %} + + {% endif %} + {% if post.tags and post.tags.length>0 %} + + {% for tag in post.tags.toArray() %} + {{ tag.name }} + {% endfor %} + + {% endif %} + + {% endif %} + {% endfor %} + {% endif %} + {% if pages %} + {% for page in pages.toArray() %} + {% if post.indexing == undefined or post.indexing %} + + {{ page.title }} + + {{ [url, post.path] | urlJoin | uriencode }} + {% if content %} + + {% endif %} + + {% endif %} + {% endfor %} + {% endif %} +