前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >LeetCode笔记:Weekly Contest 200 比赛记录

LeetCode笔记:Weekly Contest 200 比赛记录

作者头像
codename_cys
发布2021-03-28 16:10:42
3340
发布2021-03-28 16:10:42
举报

1. 题目一

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

1. 解题思路

这一题本身还是比较复杂的,需要比对所有的三元组(i,j,k)是否满足题目定义的good triplet的条件。

但是由于题目本身限制了array的长度不会超过100,因此,我们可以直接采用三重循环方式的方式直接暴力求解,即遍历所有可能的三元组,看其是否满足good triplet条件。

2. 代码实现

给出其代码实现如下:

class Solution:
    def countGoodTriplets(self, arr: List[int], a: int, b: int, c: int) -> int:
        def is_good(i, j, k):
            return abs(arr[i]-arr[j]) <= a and abs(arr[j]-arr[k]) <= b and abs(arr[i]-arr[k]) <= c
        
        n = len(arr)
        ans = 0
        for i in range(n-2):
            for j in range(i+1, n-1):
                for k in range(j+1, n):
                    if is_good(i, j, k):
                        ans += 1
        return ans

提交代码后评测得到:代码耗时1524ms,占用内存13.8MB。

而现有的最优解答耗时676ms。但是考察其代码发现其实现方式与我们没有本质区别,差别在于我们定义的is_good()函数损伤了代码性能。

2. 题目二

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

1. 解题思路

这一题坦率地说比赛的时候卡了我有一阵子,因为想不清楚多次比较之后数组的变化。当然,我们可以暴力的通过不停地pop和append的操作复现题目的操作过程,但是由于数组长度n和目标连续胜场次数k都可能非常大,因此担心暴力求解会导致超时。

因此,比较合理的想法是考虑其具体的过程然后找出规律,从而找到一个更为优雅直接的解题思路。(不过后期来看还是没能避免超时报错的命运)

现在,我们来考虑题目中描述的整体过程。

首先,如果给出的连胜次数不小于数组的长度,那么最终答案将必然是数组中的最大元素,直接返回最大值即可。

而后,我们来考虑连胜次数小于数组长度的情况。

假设我们已经进行了m次比较,那么我们一定会有如下的结论:

  1. 当前array的第一个元素必定为初始状态下的前m+1个元素中的最大值
  2. 当前array的最后m个元素一定都小于当前的第一个元素

那么,假设初始数组中位置idx上的数字为我们最终的答案,则一定有:

  1. 如果idx=0,那么arr[0]一定是arr[:k+1]中的最大数字;
  2. 如果idx>0,那么:
    1. arr[idx]一定大于它前方的所有元素中的最大值(idx-1次操作后的arr[0]);
    2. 在此时的窗口[0: k+1]中,一定不会有比它更大的数;

这里,比较麻烦的问题在于对于idx>0的情况,在经过多次操作之后,当前的窗口是有可能包含之前的操作中补充到尾部的数据的,而这些补充的数据顺序也会和初始的顺序不同,因此无法直接给出。

但是,幸运的是,由我们前述的推论,m次操作之后补充在序列最后的数字一定小于当前的第一个元素,因此也必然小于当前的arr[idx],因此,我们事实上只要处理如下情况即可:

  1. 如果idx+k<=n,那么我们只需要比较原始序列中窗口[idx: idx+k]中的数据即可;
  2. 如果idx+k>n,那么我们只需要比较原始序列中窗口[idx: n]中的数据即可。

如此,上述题目即可完成。

2. 代码实现

给出上述解题思路下的代码实现如下:

class Solution:
    def getWinner(self, arr: List[int], k: int) -> int:
        n = len(arr)
        
        def get_window(i, k):
            return arr[i: min(i+k, n)]
        
        if k >= n:
            return max(arr)
        if arr[0] == max(get_window(0, k+1)):
            return arr[0]
        max_num = arr[0]
        for i in range(1, n):
            if arr[i] < max_num:
                continue
            max_num = arr[i]
            if arr[i] == max(get_window(i, k)):
                return arr[i]
        return -1

提交代码后评测得到:耗时648ms,占用内存27.6MB。均属于当前第一梯队。

3. 当前最优代码分析

比较坑爹的是,看了一下其他人的解答,发现居然他们是暴力求解的,直接不停地进行比较操作直到连胜次数达到k。。。

我尝试了一下使用数组的pop和append操作,果然发现超时,但是当前的最优解却居然同样是相同的暴力解答思路,也是没啥想说的了。

他们暴力求解依然可以搞定的唯一原因在于他们用了python的collection库中的队列结构,它在出入队列的操作中执行效率更优。。。表示累感不爱。。。

给出他们的解答如下,有兴趣的读者可以参考一下,但反正我觉得是邪道。。。

from collections import *

class Solution:
    def getWinner(self, arr: List[int], k: int) -> int:
        if k >= len(arr) - 1:
            return max(arr)
        queue = deque(arr)
        cnt = 0
        while True:
            a = queue.popleft()
            b = queue.popleft()
            if a > b:
                cnt += 1
                queue.append(b)
                queue.appendleft(a)
            else:
                cnt = 1
                queue.append(a)
                queue.appendleft(b)
            if cnt >= k:
                return queue[0]

3. 题目三

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

1. 解题思路

这一题就基本上等同于冒泡排序了,我们只需要考虑每一行恢复到下三角矩阵时所需要进行的交换操作的次数。

考察第i行(i=0,1,2,..,n−1),当矩阵为下三角矩阵时,则其右方必有只有n−1−i个0元素,因此,我们只要找到第一个符合这一条件的行(假设为k)并将其进行移动即可。交换的次数即为k-i

需要注意的是,由于是下三角矩阵,因此,当对某一行i进行操作时,我们无需考虑找到的行中的0元素多于目标行所需的0元素个数的情况,因为在此之前的行一定已经被填充完毕了。

2. 代码实现

下面,我们依照上述解题思路给出代码实现如下:

class Solution:
    def minSwaps(self, grid: List[List[int]]) -> int:
        n = len(grid)

        def get_zero_num(arr):
            return n - len("".join([str(i) for i in arr]).rstrip('0'))

        counter = [get_zero_num(arr) for arr in grid]
        ans = 0
        for i in range(n-1):
            idx = -1
            for j, count in enumerate(counter):
                if count >= n-1-i:
                    idx = j
                    break
            if idx == -1:
                return -1
            ans += idx
            counter.pop(idx)
        return ans

提交代码测试得到:耗时572ms,占用内存14.7MB。为当前python代码提交结果中的最优算法。

4. 题目四

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

1. 解题思路

这一题就是一道中规中矩的动态规划题目,坦率地说作为一道hard的题目,多少是有点名不副实的。

下面,我们快速地给出动态规划的思路如下:

  1. 考察某一数组(不妨设为nums1)中的某一元素nums1[i]
    1. 如果该元素仅出现在当前数组中,则从该元素开始的最大路径长度为nums1[i] + dp_nums1[i+1]
    2. 如果该元素同时出现在两数组当中(假设nums2[j] == num1[i]),则从该元素开始的最大路径长度为:max(nums1[i] + dp_nums1[i+1], nums2[j] + dp_nums2[j+1])

最后,我们只需要比较dp_nums1[0]dp_nums2[0]并返回较大值即可。

2. 代码实现

我们给出上述动态规划的实现代码如下:

class Solution:
    def maxSum(self, nums1: List[int], nums2: List[int]) -> int:
        MOD = 1000000007
        
        l1 = len(nums1)
        l2 = len(nums2)
        dp = [[0 for i in range(l1+1)], [0 for i in range(l2+1)]]
        i = l1-1
        j = l2-1
        while i >= 0 and j >= 0:
            if nums1[i] > nums2[j]:
                dp[0][i] = dp[0][i+1] + nums1[i]
                i -= 1
            elif nums1[i] < nums2[j]:
                dp[1][j] = dp[1][j+1] + nums2[j]
                j -= 1
            else:
                dp[0][i] = max(nums1[i] + dp[1][j+1], nums1[i] + dp[0][i+1])
                dp[1][j] = max(nums1[i] + dp[0][i+1], nums2[j] + dp[1][j+1])
                i -= 1
                j -= 1
        while i >= 0:
            dp[0][i] = dp[0][i+1] + nums1[i]
            i -= 1
        while j >= 0:
            dp[1][j] = dp[1][j+1] + nums2[j]
            j -= 1
        return max(dp[0][0], dp[1][0]) % MOD

提交代码后评测得到:代码耗时720ms,占用内存29.4ms。为当前python代码提交结果中的最优算法。

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2020-08-02 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 1. 题目一
    • 1. 解题思路
      • 2. 代码实现
      • 2. 题目二
        • 1. 解题思路
          • 2. 代码实现
            • 3. 当前最优代码分析
            • 3. 题目三
              • 1. 解题思路
                • 2. 代码实现
                • 4. 题目四
                  • 1. 解题思路
                    • 2. 代码实现
                    相关产品与服务
                    腾讯云代码分析
                    腾讯云代码分析(内部代号CodeDog)是集众多代码分析工具的云原生、分布式、高性能的代码综合分析跟踪管理平台,其主要功能是持续跟踪分析代码,观测项目代码质量,支撑团队传承代码文化。
                    领券
                    问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档