LeetCode笔记:Weekly Contest 206 比赛记录

  • LeetCode笔记:Weekly Contest 206
    • 0. 赛后总结
    • 1. 题目一
      • 1. 解题思路
      • 2. 代码实现
    • 2. 题目二
      • 1. 解题思路
      • 2. 代码实现
    • 3. 题目三
      • 1. 解题思路
      • 2. 代码实现
    • 4. 题目四
      • 1. 解题思路
      • 2. 代码实现

0. 赛后总结

最近不知是换到中文leetcode平台之后水土不服还是怎么样,感觉真的是到了瓶颈期了,最近几次打比赛真的是一次不如一次,做起来异常不顺手。

看了一下头部几位大佬们的做题耗时,基本都还是在10分钟左右,因此基本不存在这几次的题目特别难的说法,那么就是我这边自身发挥的问题了。

感觉真的是需要休息一阵子好好调整一下了,等到国庆放假的时候好好休息一下吧,但愿之后的状态能有回暖吧。。。

{ { {(>_<)}}}

1. 题目一

给出题目一的试题链接如下:

  • 5511. 二进制矩阵中的特殊位置

1. 解题思路

这一题的关键点就是统计只出现一行和一列中的1中的元素的个数。

因此,只要统计每一行中只有一个1的行,然后再对对应元素的列看一下是否该列中也恰好只出现了一个1

2. 代码实现

给出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。姑且属于当前第一梯队。

2. 题目二

给出题目二的试题链接如下:

  • 5512. 统计不开心的朋友

1. 解题思路

这一题感觉是这次比赛中最蠢的一题,纯粹就是看题目的问题,问题描述极其绕嘴,比赛的时候看题目看了半天,还理解错了,然后就直接呵呵了。

等到最后终于把题目看明白之后,就直接暴力求解解决了。。。

本来以为是我自己的问题,然后现在去看了一下题目的评价,发现25个点赞,然后98个差评,呵呵。。。

算了,读者注意一下不开心的定义就行,是要同时满足两个条件,然后按照他说的规则直接暴力遍历一遍就行了,没啥技术含量,甚至说千万不要去想什么更精妙的解法,这题目纯粹就是靠怎么读题目而已!!!

2. 代码实现

直接给出代码实现如下:

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。

很挫的代码实现,但是懒得去看别人的实现了,反正没有什么量级上的差异,如果有兴趣的读者可以自行去看一下,这里就不多做介绍了。

3. 题目三

给出题目三的试题链接如下:

  • 5513. 连接所有点的最小费用

1. 解题思路

这一题的本质就是求最小联通图。

普遍的算法就是Dijkstra算法,一般的数据结构课上都有,不过我有点忘了,就用了他的等价算法,Dijkstra算法是每次取连通区域外的最小边添加到图中,直到整张图都连通起来。

这边的算法名字我给忘了,不过是每次取最短边使得原本不连通的两个区域能够连通起来,直到整张图都连通起来。

2. 代码实现

给出代码实现如下:

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算法。如果有感兴趣的读者可以自行实现一下,这里我就先放弃了。。。

4. 题目四

给出题目四的试题链接如下:

  • 5514. 检查字符串是否可以通过排序子字符串得到另一个字符串

1. 解题思路

这一题比赛的时候是完全没能做出来,因为一开始的思路就是错的,后来也是比赛结束之后看了一下头部几位大神们的做法,然后终于有了一些思路,后来算是终于实现出来了。

这一题的关键在于每一次的操作都是对于子序列的排序操作,因此,显然必有:原始序列中一个元素后方比他小的元素只会减少不可能会增加

因此,要判断s序列能否通过一系列操作转换为t序列,我们只需要考察:

  1. 两者所拥有的字符集合是否完全一致;
  2. 对于s中的每一个字符与t中对应的字符,s中字符后方每一个比它小的字符的数目均不少于t中对应的字符数目。

2. 代码实现

我们将其整理为代码实现即有:

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,比我们的算法高了一整个量级,因此,后续还有很大的优化空间。

需要好好看一下对方的代码实现。

感兴趣的读者可以自己先看一下,这里我就先放着了,过两天有空了再来研究一下。

你可能感兴趣的:(leetcode笔记,leetcode)