最近的事情说多不多,但是很杂乱,想起个名字基本都挺难,就偷懒写个近况。自从上次没签那个实习合同之后,我也没再继续找实习了,一是想找一个门槛稍微高一点,去了真正能学到东西的实习;二是觉得还是应该做做编程题,把之前分治法、动态规划的东西捡起来一点,这样也能增加一点找实习的成功率;三是最近看到了一个金融大模型的比赛,如果能拿到名次的话也能放到简历里充实一下经历。 ## 实习方面的情况 先说找实习的事吧,听师兄说找算法实习不需要笔试,只需要面试通过就可以了。如果是找NLP方向的实习的话,需要了解Transformer结构,BERT和它对应的变种模型(RoBERTa、XLM-RoBERTa)的基础知识,然后再加上面试时会考几道现场编程的题目。这倒是让我安心了一些,这些要补上可能都没那么难。但是也有可能有新的变化,GPT系列的LLM这么猛,NLP实习岗问一些关于这些大语言模型的事也不是没可能。所以感觉生成式语言模型的东西也可以了解一下。但总之找实习这事我没那么着急了,一是如果找一个学不太到东西的实习也比较浪费时间;二是我确实也还很欠缺NLP的基础知识,趁这段时间补补不是坏事。 ## 面试编程题准备 之后说说编程题的准备情况,反正目前就在刷牛客的编程题,目前的打算是刷完“面试必刷TOP100”之后再观察情况。刷链表那章的时候感觉还比较轻松,一到归并排序和快速排序这边上点强度就感觉搞不太定了。刷着刷着还是感觉到自己有进步了,以前学的东西慢慢能想得起来,也发现了一些新鲜的东西。虽然进度是比较缓慢的,但这样有进展的情况是我觉得满意的。后面是我刷的几道感觉比较有意思的题目。 ### BM12 单链表的排序

url: 牛客 BM12

考察知识点: 归并排序、链表操作

解决方案:

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
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
# class ListNode:
# def __init__(self, x):
# self.val = x
# self.next = None
#
# 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
#
#
# @param head ListNode类 the head node
# @return ListNode类
#
class Solution:
def findMid(self, head: ListNode) -> ListNode:
if head is None or head.next is None:
return None
fast, slow = head, head

while fast.next is not None and fast.next.next is not None:
slow = slow.next
fast = fast.next.next

return slow

def mergeList(self, left_head: ListNode, right_head: ListNode):
"""合并两个有序的链表"""
result = ListNode(-1)
cur = result

while left_head is not None and right_head is not None:
if left_head.val <= right_head.val:
cur.next = left_head
left_head = left_head.next
else:
cur.next = right_head
right_head = right_head.next
cur = cur.next

if left_head is not None:
cur.next = left_head
elif right_head is not None:
cur.next = right_head

return result.next



def sortInList(self , head: ListNode) -> ListNode:
# write code here
mid = self.findMid(head)
if mid is not None:
right_head = mid.next
mid.next = None
# 二分排序
right_head = self.sortInList(right_head)
left_head = self.sortInList(head)
# 合并
head = self.mergeList(left_head, right_head)
return head

BM16 删除有序链表中重复的元素-II

url: 牛客 BM16

考察知识点:链表操作

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
#
# 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
#
#
# @param head ListNode类
# @return ListNode类
#
class Solution:
def deleteDuplicates(self , head: ListNode) -> ListNode:
# write code here
result = ListNode(-1)
result.next = head
cur = result

while cur.next is not None and cur.next.next is not None:
if cur.next.val == cur.next.next.val:
temp = cur.next.val
# 不停循环直至删除所有值为temp的元素
while cur.next is not None and cur.next.val == temp:
cur.next = cur.next.next
else:
cur = cur.next
return result.next

BM18 二维数组查找

url: 牛客 BM18

考察知识点:二分,二维数组

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
#
# 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
#
#
# @param target int整型
# @param array int整型二维数组
# @return bool布尔型
#
class Solution:
def find_2d(self, target, array, up, down, left, right):
if up <= down and left <= right:
v_mid = (up+down) // 2
h_mid = (left+right) // 2

if array[v_mid][h_mid] < target:
# 不在左上角
return self.find_2d(target, array, v_mid+1, down, left, right) or \
self.find_2d(target, array, up, v_mid, h_mid+1, right)
elif array[v_mid][h_mid] > target:
# 不在右下角
return self.find_2d(target, array, up, v_mid-1, left, right) or \
self.find_2d(target, array, v_mid, down, left, h_mid-1)
else:
return True
return False

def Find(self , target: int, array: List[List[int]]) -> bool:
# write code here
up = 0
down = len(array) - 1
left = 0
right = len(array[0]) - 1

return self.find_2d(target, array, up, down, left, right)

BM19 寻找峰值

url: 牛客 BM19

考察知识点:二分查找

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
#
# 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
#
#
# @param nums int整型一维数组
# @return int整型
#
class Solution:
def findPeakElement(self , nums: List[int]) -> int:
# write code here
left = 0
right = len(nums) - 1
length = len(nums) - 1

while left <= right:
mid = (left+right) // 2
# 处理左右边界情况
left_value = nums[mid-1] if mid-1 >= 0 else -2**31-1
right_value = nums[mid+1] if mid+1 <= length else -2**31-1

if nums[mid] > left_value and nums[mid] > right_value:
return mid
elif nums[mid] > left_value:
left = mid + 1
else:
right = mid - 1

return -1

BM20 数组中的逆序对

url: 牛客 BM20

考察知识点:归并排序、分治法

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
43
44
45
46
47
48
49
50
51
52
#
# 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
#
#
# @param nums int整型一维数组
# @return int整型
#
class Solution:
def DC_method(self, nums: List[int], left: int, right: int):
if right <= left:
return 0
mid = (left + right) // 2
inverse_pairs_right = self.DC_method(nums, left, mid)
inverse_pairs_left = self.DC_method(nums, mid+1, right)
# 合并
inverse_pairs_combine = self.merge(nums, left, mid, right)
return inverse_pairs_left+inverse_pairs_right+inverse_pairs_combine

def merge(self, nums: List[int], left: int, mid: int, right: int):
# 左边的数组为left到mid, 右边的为mid+1到right
inverse_pairs = 0
left_point = left
right_point = mid+1

# 复制一个数组
nums_copy = [0 for i in range(right-left+1)]
p = 0
while left_point <= mid and right_point <= right:
if nums[left_point] > nums[right_point]:
nums_copy[p] = nums[right_point]
inverse_pairs += mid - left_point + 1
right_point += 1
else:
nums_copy[p] = nums[left_point]
left_point += 1
p += 1
if left_point <= mid:
nums_copy[p:right-left+1] = nums[left_point: mid+1]
else:
nums_copy[p:right-left+1] = nums[right_point: right+1]
nums[left: right+1] = nums_copy

return inverse_pairs



def InversePairs(self , nums: List[int]) -> int:
# write code here
inverse_pairs = 0
left = 0
right = len(nums) - 1
return self.DC_method(nums, left, right) % 1000000007

BM21 旋转数组的最小数字

url: 牛客 BM21

考察知识点:二分查找、分治法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
#
# 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
#
#
# @param nums int整型一维数组
# @return int整型
#
class Solution:
def minNumberInRotateArray(self, nums: List[int]) -> int:
# write code here
left = 0
right = len(nums) - 1
if right == 0:
return nums[0]

while left < right:
mid = (left+right) // 2
if nums[mid] > nums[right]:
left = mid+1
elif nums[mid] == nums[right]:
right = right - 1
else:
right = mid
return nums[left]

大语言模型比赛方面的情况

参加了一个大语言模型(ChatGLM2-6B)金融赛道的比赛,大致的要求是使用大语言模型和上市公司的年报来回答问题。这些问题有的是直接从年报中可以找出答案的问题,也就是信息提取类的问题;有的是需要通过公式计算才能得到答案的计算类问题;还有的是理解年报中的内容,根据年报内容作答的阅读理解类问题。详情可以参见: SMP 2023 ChatGLM金融大模型挑战赛。 这个比赛的周期比较长,可能有一个多月,目前初赛已经快结束了。我自我感觉没有比别人差太多吧,还登顶过一次,虽然没占几个小时就被别人挤下来了哈哈。此处必须放一下登顶的截图~

image-20230814215352266

目前当然被挤下来了,和很多人并列了第6的位置(截止到20230814 21:00)。

image-20230814215615746

这个比赛还是挺有意思的,后期可能整理一下代码把整个项目开源出来。参加这比赛一方面让我感觉到大语言模型,至少是6B这种规模的大语言模型还是很难独当一面的,它需要很多工程化的设计才能降低错误率。另一方面也是见识到了大语言模型强悍的Zero-shot/Few-shot能力,NLP研究心心念念的理解任务都可以通过指令描述、提供示例在使用很少数据的情况下完成。不管它完成得怎么样吧,反正肯定不是瞎猜的,它是真的有解决问题的潜力!

大语言模型有潜力,但也很吃算力。直接撸起袖子微调我不知道在我现有的算力上可行性有多少。这个比赛在让我学习大语言模型里Prompt工程的相关知识,希望在后续的研究也能真正用到。毕竟如果走出这个比赛之外,Meta也开源了7B、13B、70B的大语言模型llama 2。我最期待的还是33B的那款,目前还没开源,应该是我硬件能负担的最高水平了。如果能想到啥巧妙的办法用好这些家伙,说不定真能整出啥好活。

大概就是这些了吧,就先这样吧。