Leetcode 1349: The maximum number of students taking the exam (ultra-detailed solution !!!)

Give you a m * nmatrix seatsrepresentation of the seat distribution in the classroom. If the seat is bad (not available), use '#'represents; otherwise, with '.'representation.

Students can see on the left, right, upper left, upper right next to the four directions of his students answer, but students can not see him sitting directly in front of or behind the answer. Please work and returns the maximum number of students taking the exam together and can not cheat the examination room can hold.

Students must be in good condition sitting on the seat.

Example 1:

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

Example 2:

输入:seats = [[".","#"],
              ["#","#"],
              ["#","."],
              ["#","#"],
              [".","#"]]
输出:3
解释:让所有学生坐在可用的座位上。

Example 3:

输入:seats = [["#",".",".",".","#"],
              [".","#",".","#","."],
              [".",".","#",".","."],
              [".","#",".","#","."],
              ["#",".",".",".","#"]]
输出:10
解释:让学生坐在第 1、3 和 5 列的可用座位上。

prompt:

  • seats It contains only characters '.' 和``'#'
  • m == seats.length
  • n == seats[i].length
  • 1 <= m <= 8
  • 1 <= n <= 8

Problem-solving ideas

First difficult to think of a combination approach, which is to enumerate each seat and 不放two states, and then finally the optimal solution. Similar problems Leetcode 39: Total composition

class Solution:
    def maxStudents(self, seats: List[List[str]]) -> int:
        r, c = len(seats), len(seats[0])
        data = [(i, j) for i in range(r) for j in range(c) if seats[i][j] == '.']
        n = len(data)
        fan = set()

        def dfs(u):
            if u == n:
                return 0

            res = dfs(u + 1) # 不妨椅子
            i, j = data[u]
            for x, y in [[0, -1], [0, 1], [-1, -1], [-1, 1]]:
                nx, ny = i + x, j + y
                if 0 <= nx < r and 0 <= ny < c and (nx, ny) in fan:
                    break
            else:
                fan.add(data[u])
                res = max(res, dfs(u + 1) + 1) # 可以放椅子
                fan.remove(data[u])
            return res
        
        return dfs(0)

But to do so the time complexity is too high. So thinking is not there overlap computing ? This line can take the current position of the maximum number of people, determined by the state of the previous line (and the line does not matter). With this dependency, we can go through the code optimization of memory.

from functools import lru_cache
class Solution:
    def maxStudents(self, seats: List[List[str]]) -> int:
        r, c = len(seats), len(seats[0])

        @lru_cache(None)
        def dfs(x, y, pre, cur):
            if x == r:
                return 0

            if not y:
                pre, cur = cur, 0

            nex, ney = (x, y + 1) if y < c - 1 else (x + 1, 0)

            res = dfs(nex, ney, pre, cur)
            if seats[x][y] == '#':
                return res

            for i, j in ((0, -1), (-1, 1), (-1, -1)):
                nx, ny = x + i, y + j
                if 0 <= nx < r and 0 <= ny < c and \
                    ((nx == x and cur & 1 << ny) or \
                    (nx != x and pre & 1 << ny)):
                    break
            else:
                res = max(res, dfs(nex, ney, pre, cur | 1 << y) + 1)
            return res
        
        return dfs(0, 0, 0, 0)

In fact, when I saw this question, the first thought is to split the collection into two opposing collection, and then find the maximum number of collections, is not this the biggest match bipartite graph it? Here we will be seen as the odd and even columns opposite better treatment (note the odd and even lines can not be seen as the opposite, because the subject detection direction, are transverse, longitudinally upward only).

When building side, the odd side of the point by point to point even number of sides. May be present for each seat 6sides (left, right, upper left, upper right, lower left, lower right), and finally to the use of Hungarian algorithm.

class Solution:
    def maxStudents(self, seats: List[List[str]]) -> int:
        r, c = len(seats), len(seats[0])
        match = [[-1] * c for _ in range(r)]
        
        def find(node, vis):
            x, y = node
            for i, j in [[-1, -1], [0, -1], [1, -1], [-1, 1], [0, 1], [1, 1]]:
                nx, ny = i + x, j + y
                if 0 <= nx < r and 0 <= ny < c and not vis[nx][ny] and seats[nx][ny] == '.':
                    vis[nx][ny] = True
                    if match[nx][ny] == -1 or find(match[nx][ny], vis):
                        match[nx][ny] = node
                        return True
            return False
        
        res, cnt = 0, 0
        for i in range(0):
            for j in range(0, c, 2):
                if seats[i][j] != '.': continue
                vis = [[False] * c for _ in range(r)]
                if find((i, j), vis): res += 1
        
        for i in range(r):
            for j in range(c):
                if seats[i][j] == '.': cnt += 1
        return cnt - res

Other language versions of the questions I added to my GitHub Leetcode

If you have questions, I wish to point out! ! !

发布了732 篇原创文章 · 获赞 457 · 访问量 83万+

Guess you like

Origin blog.csdn.net/qq_17550379/article/details/104275858