936. Stamping The Sequence

88 篇文章 0 订阅
42 篇文章 0 订阅

You want to form a target string of lowercase letters.

At the beginning, your sequence is target.length '?' marks.  You also have a stamp of lowercase letters.

On each turn, you may place the stamp over the sequence, and replace every letter in the sequence with the corresponding letter from the stamp.  You can make up to 10 * target.length turns.

For example, if the initial sequence is "?????", and your stamp is "abc",  then you may make "abc??", "?abc?", "??abc" in the first turn.  (Note that the stamp must be fully contained in the boundaries of the sequence in order to stamp.)

If the sequence is possible to stamp, then return an array of the index of the left-most letter being stamped at each turn.  If the sequence is not possible to stamp, return an empty array.

For example, if the sequence is "ababc", and the stamp is "abc", then we could return the answer [0, 2], corresponding to the moves "?????" -> "abc??" -> "ababc".

Also, if the sequence is possible to stamp, it is guaranteed it is possible to stamp within 10 * target.length moves.  Any answers specifying more than this number of moves will not be accepted.

 

Example 1:

Input: stamp = "abc", target = "ababc"
Output: [0,2]
([1,0,2] would also be accepted as an answer, as well as some other answers.)

Example 2:

Input: stamp = "abca", target = "aabcaca"
Output: [3,0,1]

 

Note:

  1. 1 <= stamp.length <= target.length <= 1000
  2. stamp and target only contain lowercase letters.

思路:

1. 原问题是'????'到'abcs'这样的问题,在替换的时候就要考虑:不能影响之前已经替换好的部分。这个其实还不是很好解决的。如果反过来就很简单了,及从'abcs'到'????',因为这时候的目标变成了唯一的'?',相同位置覆盖,结果也是一样的,基于这个想法,可以写一个naive的版本(https://leetcode.com/problems/stamping-the-sequence/discuss/189258/C%2B%2B-Reverse-Operation-30-ms-better-than-DFS

class Solution:
    def movesToStamp(self, stamp, target):
        """
        :type stamp: str
        :type target: str
        :rtype: List[int]
        """
        n,m=len(target),len(stamp)
        s=[target]
        res=[]
        
        def remove():
            for i in range(n):
                ok,j,ti=False,0,i
                while j<m and ti<n and (s[0][ti]=='?' or s[0][ti]==stamp[j]):
                    if s[0][ti]==stamp[j]: ok=True
                    j+=1
                    ti+=1
                if ok and j==m:
                    s[0]=s[0][:i]+'?'*m+s[0][i+m:]
                    return i
            return -1
        
        while s[0]!='?'*n:
            t = remove()
            if t==-1: return []
            res.append(t)
        return res[::-1]
            

            

可惜会TLE,复杂度NNM

2. remove()函数有很多的重复计算,我们并不需要每次从头遍历,可以用event-driven的思想,只有当附近的字符变化时才有可能使得当前位置的字符变得可以匹配(需要先预处理stamp和target,https://leetcode.com/articles/stamping-the-sequence/

因为这个链接里面的代码说的很详细,所以就直接copy过来了

import collections
class Solution(object):
    def movesToStamp(self, stamp, target):
        M, N = len(stamp), len(target)

        queue = collections.deque()
        done = [False] * N
        ans = []
        A = []
        for i in range(N - M + 1):
            # For each window [i, i+M),
            # A[i] will contain info on what needs to change
            # before we can reverse stamp at i.

            made, todo = set(), set()
            for j, c in enumerate(stamp):
                a = target[i+j]
                if a == c:
                    made.add(i+j)
                else:
                    todo.add(i+j)
            A.append((made, todo))

            # If we can reverse stamp at i immediately,
            # enqueue letters from this window.
            if not todo:
                ans.append(i)
                for j in range(i, i + len(stamp)):
                    if not done[j]:
                        queue.append(j)
                        done[j] = True

        # For each enqueued letter,
        while queue:
            i = queue.popleft()

            # For each window that is potentially affected,
            # j: start of window
            for j in range(max(0, i-M+1), min(N-M, i)+1):
                if i in A[j][1]:  # This window is affected
                    A[j][1].discard(i) # Remove it from todo list of this window
                    if not A[j][1]:  # Todo list of this window is empty
                        ans.append(j)
                        for m in A[j][0]: # For each letter to potentially enqueue,
                            if not done[m]:
                                queue.append(m)
                                done[m] = True

        return ans[::-1] if all(done) else []
            

Intuition

Imagine we stamped the sequence with moves m_1, m_2, \cdotsm1​,m2​,⋯. Now, from the final position target, we will make those moves in reverse order.

Let's call the ith window, a subarray of target of length stamp.length that starts at i. Each move at position i is possible if the ith window matches the stamp. After, every character in the window becomes a wildcard that can match any character in the stamp.

For example, say we have stamp = "abca" and target = "aabcaca". Working backwards, we will reverse stamp at window 1 to get "a????ca", then reverse stamp at window 3 to get "a??????", and finally reverse stamp at position 0 to get "???????".

Algorithm

Let's keep track of every window. We want to know how many cells initially match the stamp (our "made" list), and which ones don't (our "todo" list). Any windows that are ready (ie. have no todo list), get enqueued.

Specifically, we enqueue the positions of each character. (To save time, we enqueue by character, not by window.) This represents that the character is ready to turn into a "?" in our working target string.

Now, how to process characters in our queue? For each character, let's look at all the windows that intersect it, and update their todo lists. If any todo lists become empty in this manner (window.todo is empty), then we enqueue the characters in window.made that we haven't processed yet.

Complexity Analysis

  • Time Complexity: O(N(N-M)), where M,N are the lengths of stamptarget.

  • Space Complexity: O(N(N-M)).

 

一开始怎么也看不懂,debug几个case就能容易看懂思路了。对于标准答案,自己是想到了要预处理stamp和target,也想到了用event-driven的思想优化,就是组合不起来。

不过把一对多转化为多对一的思想还是值得借鉴的。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 内容概要 《计算机试卷1》是一份综合性的计算机基础和应用测试卷,涵盖了计算机硬件、软件、操作系统、网络、多媒体技术等多个领域的知识点。试卷包括单选题和操作应用两大类,单选题部分测试学生对计算机基础知识的掌握,操作应用部分则评估学生对计算机应用软件的实际操作能力。 ### 适用人群 本试卷适用于: - 计算机专业或信息技术相关专业的学生,用于课程学习或考试复习。 - 准备计算机等级考试或职业资格认证的人士,作为实战演练材料。 - 对计算机操作有兴趣的自学者,用于提升个人计算机应用技能。 - 计算机基础教育工作者,作为教学资源或出题参考。 ### 使用场景及目标 1. **学习评估**:作为学校或教育机构对学生计算机基础知识和应用技能的评估工具。 2. **自学测试**:供个人自学者检验自己对计算机知识的掌握程度和操作熟练度。 3. **职业发展**:帮助职场人士通过实际操作练习,提升计算机应用能力,增强工作竞争力。 4. **教学资源**:教师可以用于课堂教学,作为教学内容的补充或学生的课后练习。 5. **竞赛准备**:适合准备计算机相关竞赛的学生,作为强化训练和技能检测的材料。 试卷的目标是通过系统性的题目设计,帮助学生全面复习和巩固计算机基础知识,同时通过实际操作题目,提高学生解决实际问题的能力。通过本试卷的学习与练习,学生将能够更加深入地理解计算机的工作原理,掌握常用软件的使用方法,为未来的学术或职业生涯打下坚实的基础。
Complete the Mint and Coin classes so that the coins created by a mint have the correct year and worth. - Each Mint instance has a year stamp. The update method sets the year stamp to the current_year class attribute of the Mint class. - The create method takes a subclass of Coin and returns an instance of that class stamped with the mint's year (which may be different from Mint.current_year if it has not been updated.) - A Coin's worth method returns the cents value of the coin plus one extra cent for each year of age beyond 50. A coin's age can be determined by subtracting the coin's year from the current_year class attribute of the Mint class. ```python class Mint: """A mint creates coins by stamping on years. The update method sets the mint's stamp to Mint.current_year. >>> mint = Mint() >>> mint.year 2020 >>> dime = mint.create(Dime) >>> dime.year 2020 >>> Mint.current_year = 2100 # Time passes >>> nickel = mint.create(Nickel) >>> nickel.year # The mint has not updated its stamp yet 2020 >>> nickel.worth() # 5 cents + (80 - 50 years) 35 >>> mint.update() # The mint's year is updated to 2100 >>> Mint.current_year = 2175 # More time passes >>> mint.create(Dime).worth() # 10 cents + (75 - 50 years) 35 >>> Mint().create(Dime).worth() # A new mint has the current year 10 >>> dime.worth() # 10 cents + (155 - 50 years) 115 >>> Dime.cents = 20 # Upgrade all dimes! >>> dime.worth() # 20 cents + (155 - 50 years) 125 """ current_year = 2020 def init(self): self.update() def create(self, kind): "*** YOUR CODE HERE " def update(self): " YOUR CODE HERE " class Coin: def init(self, year): self.year = year def worth(self): " YOUR CODE HERE ***" class Nickel(Coin): cents = 5 class Dime(Coin): cents = 10
06-03

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值