LeetCode笔记:Biweekly Contest 33 比赛记录

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

0. 赛后总结

这次的比赛运气不错,赛题比较简单,因此也都把题目搞定了,虽然第一题大意失荆州错了一次,但是整体排名还是首次突破了前500的,实在是非常的幸运。

如果这样的表现能是常态的话那就一本满足了,LOL

1. 题目一

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

  • 1556. Thousand Separator

1. 解题思路

这一题本身并没有太大的难度,无非就是以3位为单位对原数字进行切割然后转换为str后用.进行合并而已。

可惜我实做的时候大意了一下,对于中间的数字没有考虑清楚特殊情况,即如果他们以0开头,我们需要完整地保留这些数字,而不能简单地对其进行字符串到数字的转换

2. 代码实现

给出代码实现如下:

class Solution:
    def thousandSeparator(self, n: int) -> str:
        if n == 0:
            return "0"
        ans = []
        while n != 0:
            ans.insert(0, ("000" + str(n % 1000))[-3:])
            n = n // 1000
        return ".".join(ans).lstrip("0")

提交代码评测得到:耗时24ms,占用内存13.8MB。属于当前最优实现。

2. 题目二

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

  • 1557. Minimum Number of Vertices to Reach All Nodes

1. 解题思路

这道题如果不保证有解的话其实还是有点麻烦的,但是既然题目中已经确保题目有解的话,那么我们只要找到其中所有的起始点(即那些不是任何一条边的终点的点)即可

2. 代码实现

我们只需要将上述思路翻译成代码语言即可。

给出python实现如下:

class Solution:
    def findSmallestSetOfVertices(self, n: int, edges: List[List[int]]) -> List[int]:
        reachable = {
     }
        for x, y in edges:
            reachable[y] = reachable.get(y, []) + [x]
        return [x for x in range(n) if x not in reachable.keys()]

提交代码评测得到:耗时1640ms,占用内存52.2MB。当前最优解答的耗时为1292ms,但是看他们的解答思路,本质来说也是完全一样的,区别在于实现细节上,因此这里就不再赘述了。

3. 题目三

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

  • 1558. Minimum Numbers of Function Calls to Make Target Array

1. 解题思路

题目中的操作事实上包括两部分,加操作和乘操作,其中后者为统一操作,前者则需要独立操作。

另外,由于是从零开始,因此,乘操作是可以进行任意次的。

故而,总的操作上来说,就是:

  • 针对需要乘操作最多的元素,保持其他元素均为0,然后对这个元素进行单独操作,直到这个这些元素与需要次多乘法操作的元素需要的乘操作相同;
  • 重复上述操作,直到所有元素需要的乘法操作数据均相同。

综上所述,最终所需要的操作数目就应该是:每一个元素需要的加操作数目和所有元素中需要的最多的乘操作数目之和

2. 代码实现

将上述解题思路翻译成python代码即有:

class Solution:
    def minOperations(self, nums: List[int]) -> int:
        def get_op(n):
            op_0 = 0
            op_1 = 0
            while n != 0:
                if n % 2 == 0:
                    op_1 += 1
                    n = n // 2
                else:
                    op_0 += 1
                    n -= 1
            return op_0, op_1
        
        ans = 0
        op_1 = 0
        for n in nums:
            tmp_0, tmp_1 = get_op(n)
            ans += tmp_0
            op_1 = max(op_1, tmp_1)
        return ans + op_1

提交代码之后评测得到:耗时1032ms,占用内存21.5MB。属于当前次优方案。但是和最优执行效率的算法进行比对之后发现,本质思路上是完全一致的,区别在于:

  1. 最优方案使用了缓存机制优化了相同数字的处理;
  2. 最优方法使用二进制操作优化了算法执行效率。

故,这里,我们也不再进行深入讨论,如果读者有兴趣的话可以自行进行优化考察。

4. 题目四

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

  • 1559. Detect Cycles in 2D Grid

1. 解题思路

这一题的解题思路还是蛮清晰的,就是针对矩阵中的每一个元素,查看他是否能够构成一个环。

剩下的问题就在于如何判断环是否存在,这个逻辑事实上也比较清晰,只要从原点出发能够有两条路线汇合到同一个点那么就能够判断环的存在。我们使用一个队列就可以实现上述思路。

2. 代码实现

我们翻译上述解题思路即有:

class Solution:
    def containsCycle(self, grid: List[List[str]]) -> bool:
        n = len(grid)
        m = len(grid[0])
        state = [[0 for j in range(m)] for i in range(n)]
        
        def find_cycle(i, j):
            nonlocal state, n, m
            tag = grid[i][j]
            queue = [(i, j)]
            while queue != []:
                x, y = queue.pop(0)
                if state[x][y] == 1:
                    return True
                state[x][y] = 1
                if x-1 >= 0 and grid[x-1][y] == tag and state[x-1][y] == 0:
                    queue.append((x-1, y))
                if x+1 < n and grid[x+1][y] == tag and state[x+1][y] == 0:
                    queue.append((x+1, y))
                if y-1 >= 0 and grid[x][y-1] == tag and state[x][y-1] == 0:
                    queue.append((x, y-1))
                if y+1 < m and grid[x][y+1] == tag and state[x][y+1] == 0:
                    queue.append((x, y+1))
            return False
        
        for i in range(n):
            for j in range(m):
                if state[i][j] == 0 and find_cycle(i, j):
                    return True
        return False

提交代码评测得到:耗时2992ms,占用内存20.8MB。当前最优方案耗时1584ms,但是看了一下整体思路基本一致,因此就不再过多赘述了。

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