最近不知是换到中文leetcode平台之后水土不服还是怎么样,感觉真的是到了瓶颈期了,最近几次打比赛真的是一次不如一次,做起来异常不顺手。
看了一下头部几位大佬们的做题耗时,基本都还是在10分钟左右,因此基本不存在这几次的题目特别难的说法,那么就是我这边自身发挥的问题了。
感觉真的是需要休息一阵子好好调整一下了,等到国庆放假的时候好好休息一下吧,但愿之后的状态能有回暖吧。。。
{ { {(>_<)}}}
给出题目一的试题链接如下:
这一题的关键点就是统计只出现一行和一列中的1中的元素的个数。
因此,只要统计每一行中只有一个1的行,然后再对对应元素的列看一下是否该列中也恰好只出现了一个1。
给出python代码实现如下:
class Solution:
def numSpecial(self, mat: List[List[int]]) -> int:
ans = 0
n = len(mat)
m = len(mat[0])
for i in range(n):
eff = []
for j in range(m):
if mat[i][j] == 1:
eff.append((i, j))
if len(eff) == 1:
j = eff[0][1]
count = 0
for k in range(n):
if mat[k][j] == 1:
count += 1
if count == 1:
ans += 1
return ans
提交代码之后评测得到:耗时168ms,占用内存14.1MB。姑且属于当前第一梯队。
给出题目二的试题链接如下:
这一题感觉是这次比赛中最蠢的一题,纯粹就是看题目的问题,问题描述极其绕嘴,比赛的时候看题目看了半天,还理解错了,然后就直接呵呵了。
等到最后终于把题目看明白之后,就直接暴力求解解决了。。。
本来以为是我自己的问题,然后现在去看了一下题目的评价,发现25个点赞,然后98个差评,呵呵。。。
算了,读者注意一下不开心的定义就行,是要同时满足两个条件,然后按照他说的规则直接暴力遍历一遍就行了,没啥技术含量,甚至说千万不要去想什么更精妙的解法,这题目纯粹就是靠怎么读题目而已!!!
直接给出代码实现如下:
class Solution:
def unhappyFriends(self, n: int, preferences: List[List[int]], pairs: List[List[int]]) -> int:
n = len(pairs)
ans = 0
for i in range(n):
x, y = pairs[i]
xh = True
yh = True
for j in range(n):
if i == j:
continue
u, v = pairs[j]
if preferences[x].index(u) < preferences[x].index(y) and preferences[u].index(x) < preferences[u].index(v):
xh = False
break
if preferences[x].index(v) < preferences[x].index(y) and preferences[v].index(x) < preferences[v].index(u):
xh = False
break
for j in range(n):
if i == j:
continue
u, v = pairs[j]
if preferences[y].index(u) < preferences[y].index(x) and preferences[u].index(y) < preferences[u].index(v):
yh = False
break
if preferences[y].index(v) < preferences[y].index(x) and preferences[v].index(y) < preferences[v].index(u):
yh = False
break
if not xh:
ans += 1
if not yh:
ans += 1
return ans
提交代码之后得到:耗时472ms,占用内存27.1MB。
很挫的代码实现,但是懒得去看别人的实现了,反正没有什么量级上的差异,如果有兴趣的读者可以自行去看一下,这里就不多做介绍了。
给出题目三的试题链接如下:
这一题的本质就是求最小联通图。
普遍的算法就是Dijkstra算法,一般的数据结构课上都有,不过我有点忘了,就用了他的等价算法,Dijkstra算法是每次取连通区域外的最小边添加到图中,直到整张图都连通起来。
这边的算法名字我给忘了,不过是每次取最短边使得原本不连通的两个区域能够连通起来,直到整张图都连通起来。
给出代码实现如下:
class Solution:
def minCostConnectPoints(self, points: List[List[int]]) -> int:
n = len(points)
distances = [[abs(x[0] - y[0]) + abs(x[1] - y[1]) for y in points] for x in points]
distances = sorted((distances[x][y], x, y) for x in range(n-1) for y in range(x+1, n))
ans = 0
have_connected = [set([i]) for i in range(n)]
for d, x, y in distances:
if any(x in s and y in s for s in have_connected):
continue
s1 = -1
s2 = -1
for j, s in enumerate(have_connected):
if x in s:
s1 = j
if y in s:
s2 = j
if s1 > s2:
s1, s2 = s2, s1
have_connected.append(have_connected[s1] | have_connected[s2])
have_connected.pop(s2)
have_connected.pop(s1)
ans += d
if len(have_connected) == 1:
break
return ans
提交代码评测得到:耗时2192ms,占用内存105.6MB。
当前最优算法耗时仅为1060ms,看了一下,使用的是Dijkstra算法。如果有感兴趣的读者可以自行实现一下,这里我就先放弃了。。。
给出题目四的试题链接如下:
这一题比赛的时候是完全没能做出来,因为一开始的思路就是错的,后来也是比赛结束之后看了一下头部几位大神们的做法,然后终于有了一些思路,后来算是终于实现出来了。
这一题的关键在于每一次的操作都是对于子序列的排序操作,因此,显然必有:原始序列中一个元素后方比他小的元素只会减少不可能会增加。
因此,要判断s序列能否通过一系列操作转换为t序列,我们只需要考察:
我们将其整理为代码实现即有:
class Solution:
def isTransformable(self, s: str, t: str) -> bool:
n = len(t)
scounter = [{
c: 0 for c in "0123456789"} for _ in range(n+1)]
tcounter = [{
c: 0 for c in "0123456789"} for _ in range(n+1)]
for i in range(n-1, -1, -1):
for c in "0123456789":
scounter[i][c] = scounter[i+1][c]
tcounter[i][c] = tcounter[i+1][c]
scounter[i][s[i]] += 1
tcounter[i][t[i]] += 1
if not all(scounter[0][c] == tcounter[0][c] for c in "0123456789"):
return False
scounter_v2 = {
c: [] for c in "0123456789"}
for i in range(n):
scounter_v2[s[i]].append(i+1)
tcounter_v2 = {
c: [] for c in "0123456789"}
for i in range(n):
tcounter_v2[t[i]].append(i+1)
for c in "123456789":
for idx1, idx2 in zip(scounter_v2[c], tcounter_v2[c]):
if not all(scounter[idx1][str(k)] >= tcounter[idx2][str(k)] for k in range(int(c))):
return False
return True
上述代码提交可以通过,评测得到:耗时3332ms,占用内存104.2MB。
而当前最优代码实现耗时仅为332ms,比我们的算法高了一整个量级,因此,后续还有很大的优化空间。
需要好好看一下对方的代码实现。
感兴趣的读者可以自己先看一下,这里我就先放着了,过两天有空了再来研究一下。