【周赛】第156场-2019-9-29

目录

1-Unique Number of Occurrences-easy。哈希表

 2-Get Equal Substrings Within Budget-medium。滑动窗口

3-Remove All Adjacent Duplicates in String II-medium。栈

 4-Minimum Moves to Reach Target with Rotations-hard。BFS


1-Unique Number of Occurrences-easy。哈希表

Given an array of integers arr, write a function that returns true if and only if the number of occurrences of each value in the array is unique.

Example 1:

Input: arr = [1,2,2,1,1,3]
Output: true
Explanation: The value 1 has 3 occurrences, 2 has 2 and 3 has 1. No two values have the same number of occurrences.

Example 2:

Input: arr = [1,2]
Output: false

Example 3:

Input: arr = [-3,0,1,-3,1,1,1,-3,10,0]
Output: true

Constraints:

  • 1 <= arr.length <= 1000
  • -1000 <= arr[i] <= 1000

比较简单,考察字典

class Solution:
    def uniqueOccurrences(self, arr: List[int]) -> bool:
        if not arr:
            return True
        dic = {}
        for n in arr:
            dic[n] = dic.get(n, 0) + 1
        return len(set(dic.values())) == len(set(dic.keys()))

 2-Get Equal Substrings Within Budget-medium。滑动窗口

You are given two strings s and t of the same length. You want to change s to t. Changing the i-th character of s to i-th character of t costs |s[i] - t[i]| that is, the absolute difference between the ASCII values of the characters.

You are also given an integer maxCost.

Return the maximum length of a substring of s that can be changed to be the same as the corresponding substring of twith a cost less than or equal to maxCost.

If there is no substring from s that can be changed to its corresponding substring from t, return 0.

Example 1:

Input: s = "abcd", t = "bcdf", cost = 3
Output: 3
Explanation: "abc" of s can change to "bcd". That costs 3, so the maximum length is 3.

Example 2:

Input: s = "abcd", t = "cdef", cost = 3
Output: 1
Explanation: Each charactor in s costs 2 to change to charactor in t, so the maximum length is 1.

Example 3:

Input: s = "abcd", t = "acde", cost = 0
Output: 1
Explanation: You can't make any change, so the maximum length is 1.

Constraints:

  • 1 <= s.length, t.length <= 10^5
  • 0 <= maxCost <= 10^6
  • s and t only contain lower case English letters.

 比较简单,滑动窗口的模板题

class Solution:
    def equalSubstring(self, s: str, t: str, maxCost: int) -> int:
        if not s or not t or len(s) != len(t):
            return 0
        left = cur_cost = res = 0
        n = len(s)
        for i in range(n):
            cur_cost += abs(ord(s[i]) - ord(t[i]))
            while cur_cost > maxCost:
                cur_cost -= abs(ord(s[left]) - ord(t[left]))
                left += 1
            res = max(res, i-left+1)
        return res

3-Remove All Adjacent Duplicates in String II-medium。栈

Given a string s, a k duplicate removal consists of choosing k adjacent and equal letters from s and removing them causing the left and the right side of the deleted substring to concatenate together.

We repeatedly make k duplicate removals on s until we no longer can.

Return the final string after all such duplicate removals have been made.

It is guaranteed that the answer is unique.

Example 1:

Input: s = "abcd", k = 2
Output: "abcd"
Explanation: There's nothing to delete.

Example 2:

Input: s = "deeedbbcccbdaa", k = 3
Output: "aa"
Explanation: 
First delete "eee" and "ccc", get "ddbbbdaa"
Then delete "bbb", get "dddaa"
Finally delete "ddd", get "aa"

Example 3:

Input: s = "pbbcggttciiippooaais", k = 2
Output: "ps"

Constraints:

  • 1 <= s.length <= 10^5
  • 2 <= k <= 10^4
  • s only contains lower case English letters.

栈的题。题意比较清楚,难的是如何写的比较简洁。之前想的是如果只遍历一次的话,无法通过频数K去pop元素,但其实栈内元素可以记录每个字符出现的频数,遇到相同的字符看看频数有否超过k,一旦==k就会被pop。

# DIY的做法
class Solution:
    def removeDuplicates(self, s: str, k: int) -> str:
        if not s or k == 0:
            return s
        if k == 1:
            return ""
        s_lst = list(s)
        st = []
        while True:
            tmp = []
            n = len(s_lst)
            flag = False
            i = 0
            while i < n:
                if i+1 < n and s_lst[i] == s_lst[i+1]:
                    j = i
                    while j+1 < n and s_lst[j] == s_lst[j+1]:
                        tmp.append(s_lst[j])
                        j += 1
                    if j-i+1 >= k:
                        flag = True
                        remain = (j-i+1)%k
                        for m in range(remain):
                            st.append(s_lst[i])
                    else:
                        for m in range(i, j+1):
                            st.append(s_lst[m])
                    i = j+1
                else:
                    st.append(s_lst[i])
                    i += 1
            if not flag or not st:
                break
            s_lst = st
            st = []
        return ''.join(st)

# 简洁的做法
class Solution:
    def removeDuplicates(self, s: str, k: int) -> str:
        if not s or k == 0:
            return s
        if k == 1:
            return ""
        st = []
        n = len(s)
        for i in range(n):
            if not st or st[-1][0] != s[i]:
                st.append([s[i], 1])
            else:
                if st[-1][1] + 1 >= k:
                    st.pop()
                else:
                    st[-1][1] += 1
        ans = []
        for n in st:
            ans.append(n[0]*n[1])
        return ''.join(ans)

 4-Minimum Moves to Reach Target with Rotations-hard。BFS

In an n*n grid, there is a snake that spans 2 cells and starts moving from the top left corner at (0, 0) and (0, 1). The grid has empty cells represented by zeros and blocked cells represented by ones. The snake wants to reach the lower right corner at (n-1, n-2) and (n-1, n-1).

In one move the snake can:

  • Move one cell to the right if there are no blocked cells there. This move keeps the horizontal/vertical position of the snake as it is.
  • Move down one cell if there are no blocked cells there. This move keeps the horizontal/vertical position of the snake as it is.
  • Rotate clockwise if it's in a horizontal position and the two cells under it are both empty. In that case the snake moves from (r, c) and (r, c+1) to (r, c) and (r+1, c).
  • Rotate counterclockwise if it's in a vertical position and the two cells to its right are both empty. In that case the snake moves from (r, c) and (r+1, c) to (r, c) and (r, c+1).

Return the minimum number of moves to reach the target.

If there is no way to reach the target, return -1.

Example 1:

 

Input: grid = [[0,0,0,0,0,1],
               [1,1,0,0,1,0],
               [0,0,0,0,1,1],
               [0,0,1,0,1,0],
               [0,1,1,0,0,0],
               [0,1,1,0,0,0]]
Output: 11
Explanation:
One possible solution is [right, right, rotate clockwise, right, down, down, down, down, rotate counterclockwise, right, down].

Example 2:

Input: grid = [[0,0,1,1,1,1],
               [0,0,0,0,1,1],
               [1,1,0,0,0,1],
               [1,1,1,0,0,1],
               [1,1,1,0,0,1],
               [1,1,1,0,0,0]]
Output: 9

Constraints:

  • 2 <= n <= 100
  • 0 <= grid[i][j] <= 1
  • It is guaranteed that the snake starts at empty cells.

原先以为是比较典型的BFS,但其实是道难题,需要考虑理解清楚题意,就是蛇身有哪几个变换方向,在它是横着还是竖着的时候能进行什么位置变换是不同的。

  • 三维visited数组的设定要增加一个标志位就是横竖,如果只打算把蛇身抽象成一个点,比如在此选取蛇尾
  • 但以传统的BFS视角也能做。能唯一标识蛇位置的是两个坐标,所以这里visited设置成一个set,存储当前遍历过的位置。然后对于蛇的不同状态(横 or 竖)根据题意,横着是只能顺时针转,竖着时只能逆时针变换,一开始理解错了,以为顺逆都可以,其实不同
  • 然后还有一点就是横竖时都可以向下和向右走
# 解法1
from collections import deque
class Solution:
    def minimumMoves(self, grid: List[List[int]]) -> int:
        if not grid:
            return 0
        n = len(grid)
        q = deque([(0, 0, 0)])
        used = [[[-1]*n for _ in range(n)] for _ in range(2)]
        used[0][0][0] = 0
        while q:
            p, c, r = q.popleft()
            d = used[p][c][r] + 1
            if p == 0: # it means vertical look
                if r+2 < n and grid[c][r+2] == 0 and used[0][c][r+1] == -1: # one down
                    used[0][c][r+1] = d
                    q.append((0, c, r+1))
                if c+1 < n and grid[c+1][r] == grid[c+1][r+1] == 0 and used[0][c+1][r] == -1: # two right
                    used[0][c+1][r] = d
                    q.append((0, c+1, r))
                if c+1 < n and grid[c+1][r] == grid[c+1][r+1] == 0 and used[1][c][r] == -1: # rotate
                    used[1][c][r] = d
                    q.append((1, c, r))
            else: # horizontal look
                if r+1 < n and grid[c][r+1] == grid[c+1][r+1] == 0 and used[1][c][r+1] == -1: # two down
                    used[1][c][r+1] = d
                    q.append((1, c, r+1))
                if c+2 < n and grid[c+2][r] == 0 and used[1][c+1][r] == -1: # one right
                    used[1][c+1][r] = d
                    q.append((1, c+1, r))
                if r+1 < n and grid[c][r+1] == grid[c+1][r+1] == 0 and used[0][c][r] == -1: # rotate
                    used[0][c][r] = d
                    q.append((0, c, r))
        return used[0][n-1][n-2]

# 普通的二维做法
class Solution:
    def minimumMoves(self, grid: List[List[int]]) -> int:
        if not grid:
            return 0
        n = len(grid)
        visited = set()
        q = [(0, 0, 0, 1)]
        visited.add((0, 0, 0, 1))
        res = -1
        target = (n-1, n-2, n-1, n-1)
        while q:
            res += 1
            for i in range(len(q)):
                cur = q.pop(0)
                if cur == target:
                    return res
                x1, y1, x2, y2 = cur
                if x1 == x2: # horizontal look
                    if y2 + 1 < n and grid[x1][y2+1] == 0: # one right
                        tmp = (x1, y1+1, x2, y2+1)
                        if tmp not in visited:
                            visited.add(tmp)
                            q.append(tmp)
                    if x1 + 1 < n and grid[x1+1][y1] == 0 and grid[x1+1][y2] == 0: # two down
                        tmp = (x1+1, y1, x2+1, y2)
                        if tmp not in visited:
                            visited.add(tmp)
                            q.append(tmp)
                    if x1 + 1 < n and grid[x1+1][y1] == 0 and grid[x1+1][y1+1] == 0: # clockwise
                        tmp = (x1, y1, x2+1, y1)
                        if tmp not in visited:
                            visited.add(tmp)
                            q.append(tmp)
                else: # vertical look
                    if y1 + 1 < n and grid[x1][y1+1] == 0 and grid[x2][y2+1] == 0: # two right
                        tmp = (x1, y1+1, x2, y2+1)
                        if tmp not in visited:
                            visited.add(tmp)
                            q.append(tmp)
                    if x2 + 1 < n and grid[x2+1][y2] == 0: # one down
                        tmp = (x1+1, y1, x2+1, y1)
                        if tmp not in visited:
                            visited.add(tmp)
                            q.append(tmp)
                    if y1 + 1 < n and grid[x1][y1+1] == 0 and grid[x2][y1+1] == 0: # counter clockwise
                        tmp = (x1, y1, x1, y1+1)
                        if tmp not in visited:
                            visited.add(tmp)
                            q.append(tmp)
        return -1

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值