Given a rectangle of size n
x m
, find the minimum number of integer-sided squares that tile the rectangle.
Example 1:
Input: n = 2, m = 3
Output: 3
Example 2:
Input: n = 5, m = 8
Output: 5
Example 3:
Input: n = 11, m = 13
Output: 6
Constraints:
1 <= n <= 13
1 <= m <= 13
据说这是一篇有paper的题目,paper解法比较复杂,不适合LeetCode写,首先感谢https://blog.csdn.net/qq_17550379/article/details/102787329提供快速的写法。
思路一: 铺地砖的问题可以压缩成一个int表示某行铺的情况(https://blog.csdn.net/taoqick/article/details/22720783),也可以记录一下某列最多铺了多少行,然后依次考虑每行铺满了没有。。。这是一种比较通用的思路。在这题里,要铺的正方形从大到小变化,要知道上届不光是两个边界,还有可能右边铺了更高的,所以用get_largest先求一下上届,然后贪心地去尝试。。
class Solution:
def tilingRectangle(self, n, m):
res = m*n
def get_largest(ht,n,m,idx):
upper = min(m-idx, n-ht[idx])
ret = 1
while (ret < upper and ht[idx] == ht[idx+ret]):
ret += 1
return ret
def dfs(ht, moves):
nonlocal res
if all(h == n for h in ht):
res = min(res, moves)
return
if moves >= res:
return
idx = ht.index(min(ht))
largest = get_largest(ht,n,m,idx)
for i in range(largest, 0, -1):# 正方形大小
nht = ht[:]
print(ht[idx:idx+i])
for j in range(i): # 正方形放入
nht[idx + j] += i
dfs(nht, moves + 1)
dfs([0] * m, 0)
return res
思路二:思路二比较trick,搞成横切,竖切,包围三种状态,至于为什么只有这三种,感觉是从例子里观察出来的,数据范围更大确实有可能有更多情况,个人并不喜欢这个解法
from functools import lru_cache
class Solution:
def tilingRectangle(self, n, m):
@lru_cache(None)
def dfs(x, y):
if (x == 1):
return y
elif (y == 1):
return x
elif (x == y):
return 1
res = n*m
for i in range(1, ((x >> 1) + 1)):
res = min(res, dfs(x - i, y) + dfs(i, y))
for i in range(1, ((y >> 1) + 1)):
res = min(res, dfs(x, y - i) + dfs(x, i))
for edge in range(1, min(x, y) - 1):
for i in range(1, x - edge):
for j in range(1, y - edge):
res = min(res, 1 + dfs(i, edge + j) +
dfs(i + edge, y - edge - j) + #bug1: i+x
dfs(x - i - edge, y - j) +
dfs(x - i, j))
return res
return dfs(n,m)