[Leetcode Weekly Contest]175

链接:LeetCode

[Leetcode]1346. 检查整数及其两倍数是否存在

给你一个整数数组 arr,请你检查是否存在两个整数 N 和 M,满足 N 是 M 的两倍(即,N = 2 * M)。
更正式地,检查是否存在两个下标 i 和 j 满足:

  • i != j
  • 0 <= i, j < arr.length
  • \(arr[i] == 2 * arr[j]\)

示例 1:
输入:arr = \([10,2,5,3]\)
输出:true
解释:N = 10 是 M = 5 的两倍,即 10 = 2 * 5 。

注意,一种特殊情况是0,要计算其两倍是否在数组中,要判断其下标是否相同。

class Solution:
    def checkIfExist(self, arr: List[int]) -> bool:
        n = len(arr)
        for i in range(n):
            for j in range(n):
                if i!=j and arr[i]*2 == arr[j]:
                    return True
        return False

[Leetcode]1347. 制造字母异位词的最小步骤数

给你两个长度相等的字符串\(s\)\(t\)。每一个步骤中,你可以选择将\(t\)中的 任一字符 替换为 另一个字符。
返回使\(t\)成为\(s\)的字母异位词的最小步骤数。
字母异位词指字母相同,但排列不同的字符串。

示例 1:
输出:s = "bab", t = "aba"
输出:1
提示:用 'b' 替换 t 中的第一个 'a',t = "bba" 是 s 的一个字母异位词。

要判断最小步骤数,只需要知道\(s\)中每个字符比\(t\)多个个数即可。

import collections
class Solution:
    def minSteps(self, s: str, t: str) -> int:
        count1,count2 = collections.Counter(s),collections.Counter(t)
        res = 0
        for ch in count1:
            res += max(0,count1[ch]-count2[ch])
        return res

[Leetcode]1348. 推文计数

请你实现一个能够支持以下两种方法的推文计数类 TweetCounts:

  1. recordTweet(string tweetName, int time)
    记录推文发布情况:用户 tweetName 在 time(以 秒 为单位)时刻发布了一条推文。
  2. getTweetCountsPerFrequency(string freq, string tweetName, int startTime, int endTime)
    返回从开始时间 startTime(以 秒 为单位)到结束时间 endTime(以 秒 为单位)内,每 分 minute,时 hour 或者 日 day (取决于 freq)内指定用户 tweetName 发布的推文总数。
    freq 的值始终为 分 minute,时 hour 或者 日 day 之一,表示获取指定用户 tweetName 发布推文次数的时间间隔。
    第一个时间间隔始终从 startTime 开始,因此时间间隔为 \([startTime, startTime + delta*1>, [startTime + delta*1, startTime + delta*2>, [startTime + delta*2, startTime + delta*3>, ... , [startTime + delta*i, min(startTime + delta*(i+1), endTime + 1)>\),其中 i 和 delta(取决于 freq)都是非负整数。

这是一道业务题,其唯一的技巧在于插入和查找的时候,采用二分查找来加速即可。

import collections
class TweetCounts:
    def __init__(self):
        self.record = collections.defaultdict(list)

    def recordTweet(self, tweetName: str, time: int) -> None:
        times = self.record[tweetName]
        index = self.gethi(times,time)
        times.insert(index,time)

    # 查找第一个>=time的索引
    def gethi(self,times,time):
        if not times:
            return 0
        lo,hi = 0,len(times)-1
        while lo <= hi:
            mid = lo+((hi-lo)>>1)
            if time <= times[mid]:
                hi = mid-1
            else:
                lo = mid + 1
        return lo

    def getTweetCountsPerFrequency(self, freq: str, tweetName: str, startTime: int, endTime: int) -> List[int]:
        if freq == 'minute':
            delta = 60
        if freq == 'hour':
            delta = 3600
        if freq == 'day':
            delta = 3600 * 24
        res = []
        times = self.record[tweetName]
        while startTime <= endTime:
            lastTime = min(startTime+delta,endTime+1)
            num = self.getNum(times,startTime,lastTime)  # [startTime,lastTime>
            res.append(num)
            startTime += delta
        return res

    def getNum(self,nums,loTarget,hiTarget):
        lo = self.gethi(nums,loTarget)
        hi = self.gethi(nums,hiTarget)
        return hi-lo



# Your TweetCounts object will be instantiated and called as such:
# obj = TweetCounts()
# obj.recordTweet(tweetName,time)
# param_2 = obj.getTweetCountsPerFrequency(freq,tweetName,startTime,endTime)

[Leetcode]5335. 参加考试的最大学生数

给你一个\(m * n\)的矩阵 seats 表示教室中的座位分布。如果座位是坏的(不可用),就用 '#' 表示;否则,用 '.' 表示。
学生可以看到左侧、右侧、左上、右上这四个方向上紧邻他的学生的答卷,但是看不到直接坐在他前面或者后面的学生的答卷。请你计算并返回该考场可以容纳的一起参加考试且无法作弊的最大学生人数。
学生必须坐在状况良好的座位上。

输入:seats =
[["#",".","#","#",".","#"],
[".","#","#","#","#","."],
["#",".","#","#",".","#"]]
输出:4
解释:教师可以让 4 个学生坐在可用的座位上,这样他们就无法在考试中作弊。

本来使用备忘录+递归,结果超时了。正确的做法是用 状压DP
在题目中也提示的很明显,\(1 <= m <= 8,1 <= n <= 8\),说明每一行只有\(2^8=256\)个状态,并且这一行状态至于上一行有关,那么我们可以构造一个DP,并且\(dp[i][state]\)代表第\(i\)行在\(state\)状态下的最大学生数。

可以认为,在每一个座位上只有坐和不坐两种可能,那么每一行便只有\(2^8=256\)个状态。如果使用记忆化搜索,得在全局进行搜索,搜索空间就很大了,这大大加大了时间复杂度。

特别的,这里还用了一个辅助数组O,记录每个状态下学生的个数(每一个状态的每个1代表是坐了一个学生,0代表没有坐学生),用辅助数组a记录seats原本的状态(每一个状态的每个1代表是‘#’,0代表‘.’)。

这里使用位运算,计算1的个数和位置,也是很值得学习的。

在进行遍历时,首先判断(j & a[i]==0) and (j & (j>>1)==0) and(j & (j<<1))==0,意思是1、当前状态下,没有学生在‘#’的位置上;2、当前状态下,没有学生坐在另一个学生左边;3、当前状态下,没有学生坐在另一个学生右边。这便确定好了该行的状态,然后利用状态转移方程:
\[ dp[i+1][j] = max(dp[i+1][j],dp[i][k]+o[j]) k=0,1,2,...1<<m \]
可以通过上一行的结果来推算出这一行在该状态下的结果。当然,由于学生的左上、右上也不能坐人,则还需要判断一个条件,即 (j & (k>>1) == 0) and (j & (k<<1) == 0)。这样就可以,从上而下,推出每一行每一个状态的最大学生数。
最后,只需要返回最后一行的所有状态的最大值即可。

class Solution:
    def maxStudents(self, seats: List[List[str]]) -> int:
        n,m = len(seats),len(seats[0])
        o = [0 for _ in range(1<<m)]
        for i in range(1<<m):
            o[i] = o[i>>1] + (i&1)
        dp = [[0 for _ in range(1<<m)] for _ in range(n+1)]
        a = [0 for _ in range(n)]
        for i in range(n):
            for j in range(m):
                if seats[i][j] == '#':
                    a[i] |= 1<<j
        for i in range(n):
            for j in range(1<<m):
                if (j & a[i]==0) and (j & (j>>1)==0) and(j & (j<<1))==0 :
                    for k in range(1<<m):
                        if (j & (k>>1) == 0) and (j & (k<<1) == 0):
                            dp[i+1][j] = max(dp[i+1][j],dp[i][k]+o[j])
        return max(dp[n])

猜你喜欢

转载自www.cnblogs.com/hellojamest/p/12290237.html