LeetCode[929,930,931,932](周赛108)总结

LeetCode[929,930,931,932](周赛108)总结

本次周赛的地址为:https://leetcode-cn.com/contest/weekly-contest-108

929. 独特的电子邮件地址

  • 题目难度Easy

每封电子邮件都由一个本地名称和一个域名组成,以 @ 符号分隔。

例如,在 [email protected]中, alice 是本地名称,而 leetcode.com 是域名。

除了小写字母,这些电子邮件还可能包含 ',''+'

如果在电子邮件地址的本地名称部分中的某些字符之间添加句点('.'),则发往那里的邮件将会转发到本地名称中没有点的同一地址。例如,"[email protected][email protected] 会转发到同一电子邮件地址。 (请注意,此规则不适用于域名。)

如果在本地名称中添加加号('+'),则会忽略第一个加号后面的所有内容。这允许过滤某些电子邮件,例如 [email protected] 将转发到 [email protected]。 (同样,此规则不适用于域名。)

可以同时使用这两个规则。

给定电子邮件列表 emails,我们会向列表中的每个地址发送一封电子邮件。实际收到邮件的不同地址有多少?

示例:

输入:["[email protected]","[email protected]","[email protected]"]
输出:2
解释:实际收到邮件的是 "[email protected]" 和 "[email protected]"。

提示:

  • 1 <= emails[i].length <= 100
  • 1 <= emails.length <= 100
  • 每封 emails[i] 都包含有且仅有一个 '@' 字符。

解题思路

这道题可以是一个比较简单的字符串题。主要就是先以@为间隔,将本地名称和域名分割开。然后把字符串的本地名称部分的.给去掉,把+号后面的字符删除。然后再和域名拼接到一起。判断是否已经出现过后,通过一个list进行存储。最后返回这个list的长度。

代码:

class Solution:
    def numUniqueEmails(self, emails):
        """
        :type emails: List[str]
        :rtype: int
        """
        list = []
        for email in emails:
            email1, email2 = email.split("@")
            email1 = email1.split("+")[0]
            email1 = email1.replace('.', '')
            email = email1 + '@' + email2
            if email not in list:
                list.append(email)
        return len(list)

其中,list的方式可以通过set()来进行一定的精简。set是Python中的一个类型,它不包含重复的元素,会自动替我们判断元素是否已出现,如果已经出现过了,则会自动将该元素删除。

优化代码:

class Solution:
    def numUniqueEmails(self, emails):
        """
        :type emails: List[str]
        :rtype: int
        """
        list = set()
        for email in emails:
            email1, email2 = email.split("@")
            email1 = email1.replace('.', '').split("+")[0]
            email = email1 + '@' + email2
            list.add(email)
        return len(list)

930. 和相同的二元子数组

  • 题目难度Medium

在由若干 01 组成的数组 A 中,有多少个和为 S非空子数组。

示例:

输入:A = [1,0,1,0,1], S = 2
输出:4
解释:
如下面黑体所示,有 4 个满足题目要求的子数组:
[1,0,1,0,1]
[1,0,1,0,1]
[1,0,1,0,1]
[1,0,1,0,1]

提示:

  1. A.length <= 30000
  2. 0 <= S <= A.length
  3. A[i]01

解题思路

这道题的整体思路其实非常简单,只需要遍历一次数组A,然后将当前的子数组求和得到一个sum

  • 如果sum<S,则说明当前的子数组不够大,继续向后遍历。
  • 如果sum ==S,则说明是符合条件的子数组,计数器加一。同时,因为子数组的头部会出现有多个0元素的情况,而每去掉一个头部的0元素,子数组的和sum仍等于S。因此,还需要统计子数组头部0元素的个数。如果有n0元素,则该情况下满足要求的子数组实际上有n+1个。
  • 如果sum>S,则需要删除子数组第一个1元素及其之前的全部元素。再根据其头部的0元素个数进行子数组的数量统计。

代码:

class Solution:
    def numSubarraysWithSum(self, A, S):
        """
        :type A: List[int]
        :type S: int
        :rtype: int
        """
        l = []
        count = 0
        sum = 0
        for i in A:
            l.append(i)
            sum += i
            if sum > S:
                while l[0] == 0:
                    del l[0]
                del l[0]
                sum -= 1
            if sum == S:
                if 1 in l:
                    count += l.index(1) + 1
                else:
                    count += len(l)
        return count

通过阅读这次周赛第一名选手cai_lw的代码,学习到了一个更加简单的方式。

使用一个字典保存数组某个位置之前的数组和,然后遍历数组求和,这样当我们求到一个位置的和的时候,向前找sum-k是否在数组中,如果在的话,更新结果为之前的结果+1。同时,当前这个sum出现的次数就多了一次。

优化代码:

from collections import defaultdict
class Solution:
    def numSubarraysWithSum(self, A, S):
        """
        :type A: List[int]
        :type S: int
        :rtype: int
        """
        d=defaultdict(lambda:0)
        ps=0
        ans=0
        for a in A:
            d[ps]+=1
            ps+=a
            ans+=d[ps-S]
        return ans

还是不是很理解这个思路。回头继续思考。


931. 下降路径最小和

  • 题目难度Medium

给定一个方形整数数组 A,我们想要得到通过 A下降路径最小和。

下降路径可以从第一行中的任何元素开始,并从每一行中选择一个元素。在下一行选择的元素和当前行所选元素最多相隔一列。

示例:

输入:[[1,2,3],[4,5,6],[7,8,9]]
输出:12
解释:
可能的下降路径有:
  • [1,4,7], [1,4,8], [1,5,7], [1,5,8], [1,5,9]
  • [2,4,7], [2,4,8], [2,5,7], [2,5,8], [2,5,9], [2,6,8], [2,6,9]
  • [3,5,7], [3,5,8], [3,5,9], [3,6,8], [3,6,9]

和最小的下降路径是 [1,4,7],所以答案是 12

提示:

  1. 1 <= A.length == A[0].length <= 100
  2. -100 <= A[i][j] <= 100

解题思路

这是一个动态规划的问题,我当时的思路是从第一层的节点开始,选择下一层最小可以接触到的最小节点进行连接,并迭代下去得到结果。

但是如果这样做的话,得到的效果其实只是从第一层节点向下降能得到的最小路径。

而在这个过程中,为了追求下层节点的最小值,而一起向值较小的下层节点靠拢,而忽略掉很多更优秀的路径。

错误代码:

class Solution:
    def minFallingPathSum(self, A):
        """
        :type A: List[List[int]]
        :rtype: int
        """
        so = float("inf")
        for i in range(len(A[0])):
            do  = A[0][i]
            index = i
            for j in range(1, len(A)):
                if index == 0:
                    temp = min(A[j][index], A[j][index + 1])
                    index = A[j][index : index + 2].index(temp)
                    do += temp
                elif index == len(A[0]):
                    temp = min(A[j][index - 1], A[j][index])
                    index = A[j][index -1:].index(temp)
                    do += temp
                else:
                    temp = min(A[j][index -  1:index + 2])
                    index = A[j][index -1:index + 2].index(temp)
                    do += temp
            if do < so:
                so = do
        return so

而实际上这道动态规划题目的解题思路应该为,以下一层的节点为目标,获取到上一层可以接触到的三个相邻节点,并选择最小的值进行连接。这样做得到的结果就是:从第一层节点到当前位置的最小路径。

用图片来展示,即为下图:

img

正确代码:

class Solution(object):
    def minFallingPathSum(self, A):
        """
        :type A: List[List[int]]
        :rtype: int
        """
        n = len(A)
        dp = A[0][::]
        for row in A[1:]:
            ndp = row[::]
            
            for i in range(n):
                candidates = [dp[i]]
                if i:
                    candidates.append(dp[i-1])
                if i != n-1:
                    candidates.append(dp[i+1])
                ndp[i] += min(candidates)
            dp = ndp
        return min(dp)

932. 漂亮数组

  • 题目难度Medium

对于某些固定的 N,如果数组 A 是整数 1, 2, ..., N 组成的排列,使得:

对于每个 i < j,都不存在 k 满足 i < k < j 使得 A[k] * 2 = A[i] + A[j]

那么数组 A 是漂亮数组。

给定 N,返回任意漂亮数组 A(保证存在一个)。

示例 1:

输入:4
输出:[2,1,4,3]

示例 2:

输入:5
输出:[3,1,2,5,4]

提示:

  • 1 <= N <= 1000

解题思路

我没有理解的很透彻,因此就照搬他人的说法了。

可以先从题目的要求看:因为2*A[k]是偶数,所以只需要保证A[i]A[j]为奇数和偶数,就可以满足这个性质。

而如何在更长的数组中满足该性质呢?递归就可以了。其中有一个要点要注意。如果需要满足题目的要求,则奇数的数量总是和偶数相等,或是更多的。因此,在构建的过程中,记得将奇数的那一部分设置为可能更大的那一部分进行递归。

至于递归的边界条件N==1时,其实令这个元素的值等于任意整数似乎都可以,比如5,虽然这样得到的数组元素值很大,但是依然满足条件。但是为了美观,选择令其为1即可。

正确代码:

class Solution(object):
    def beautifulArray(self, N):
        """
        :type N: int
        :rtype: List[int]
        """
        if N==1:
            return [1]
        else:
            l=self.beautifulArray(N//2)
            r=self.beautifulArray(N-N//2)
            return [x*2 for x in l]+[x*2-1 for x in r]

猜你喜欢

转载自blog.csdn.net/hwl19951007/article/details/83512942