In a gold mine grid
of size m * n
, each cell in this mine has an integer representing the amount of gold in that cell, 0
if it is empty.
Return the maximum amount of gold you can collect under the conditions:
- Every time you are located in a cell you will collect all the gold in that cell.
- From your position you can walk one step to the left, right, up or down.
- You can't visit the same cell more than once.
- Never visit a cell with
0
gold. - You can start and stop collecting gold from any position in the grid that has some gold.
Example 1:
Input: grid = [[0,6,0],[5,8,7],[0,9,0]] Output: 24 Explanation: [[0,6,0], [5,8,7], [0,9,0]] Path to get the maximum gold, 9 -> 8 -> 7.
Example 2:
Input: grid = [[1,0,7],[2,0,6],[3,4,5],[0,3,0],[9,0,20]] Output: 28 Explanation: [[1,0,7], [2,0,6], [3,4,5], [0,3,0], [9,0,20]] Path to get the maximum gold, 1 -> 2 -> 3 -> 4 -> 5 -> 6 -> 7.
Constraints:
1 <= grid.length, grid[i].length <= 15
0 <= grid[i][j] <= 100
- There are at most 25 cells containing gold.
Accepted
15,873
Submissions
25,139
-------------------------------------------------------------------------------------------
深度优先遍历,注意从dfs退出后要把记录给清掉,但是这样还是会重复遍历,为了不重复遍历,可以把路径作为dict的key来优化结果(优化一)。理想情况下,从(r,c)开始遍历一次复杂度是O(m*n),每个节点都开始的话复杂度是O(m*n*m*n)。第二个m*n更大一些,但是起点通常都是度为1或者度为2且右上拐角(优化二)。以下是优化二的代码,虽然DFS的时候有重复:
class Solution:
#最好情况下复杂度是m*n
def dfs(self, grid, r, c, seen):
m, n = len(grid), len(grid[0])
cur,max_nxt = grid[r][c],0
for (dr, dc) in [(1, 0), (0, 1), (-1, 0), (0, -1)]:
nr, nc = r + dr, c + dc
#To improve 2: 把路径作为一个字典
if ((nr, nc) not in seen) and nr >= 0 and nr < m and nc >= 0 and nc < n and grid[nr][nc] != 0:
seen.add((nr, nc))
nxt = self.dfs(grid, nr, nc, seen)
seen.remove((nr, nc)) #bug2
max_nxt = nxt if nxt > max_nxt else max_nxt #bug1: max_nxt = nxt if nxt > max_nxt else nxt
return max_nxt + cur
#improvement1: 只有度为1和度为2的可以搞
def be_start(self, grid, r, c):
cnt = 0
m, n = len(grid), len(grid[0])
for (dr, dc) in [(1, 0), (0, 1), (-1, 0), (0, -1)]:
nr, nc = r + dr, c + dc
if (nr >= 0 and nr < m and nc >= 0 and nc < n and grid[nr][nc] != 0):
cnt += 1
if (cnt <= 1):
return True
return cnt == 2 and r+1<m and grid[r+1][c] != 0 and c+1<n and grid[r][c+1] != 0 #bug3 forget cnt==2
def getMaximumGold(self, grid):
m, n = len(grid), len(grid[0])
res = 0
for i in range(m):
for j in range(n):
if (grid[i][j] != 0 and self.be_start(grid,i,j)):
seen = {(i,j)}
cur = self.dfs(grid, i, j, seen)
res = max(res, cur)
return res
s = Solution()
print(s.getMaximumGold([[1,2,3],[4,5,6],[7,8,9]]))
网上别人用优化一的代码,看看就行,如果量比较大操作性不是很强:
def getMaximumGold(self, grid: List[List[int]]) -> int:
m, n, q, goldCellId, ans = len(grid), len(grid[0]), [], 0, 0
oneCellTrace = [[0] * n for _ in range(m)]
for i in range(m):
for j in range(n):
if grid[i][j]:
oneCellTrace[i][j] = 1 << goldCellId
goldCellId += 1
q.append((i, j, grid[i][j], oneCellTrace[i][j]))
for i, j, sum, trace in q:
ans = max(sum, ans)
for r, c in ((i + 1, j), (i - 1, j), (i, j + 1), (i, j - 1)):
if r >= 0 and r < m and c >= 0 and c < n and grid[r][c] and not (trace & oneCellTrace[r][c]):
q.append((r, c, grid[r][c] + sum, trace | oneCellTrace[r][c]))
return ans
以下是扩展问题:
-------------------------------------------------------------------------------------------
Given a n*n array like the following example. A man could only move up down left and right without oblique movement. BTW, the man could only arrive when num[i][j] is a number instead of '*'. At the same time, no num circle could be generated in n*n array. How could we get the maximum num sum?
nums = [['*','*','4','*','*','1','*'],
['*','1','2','3','*','*','*'],
['*','1','*','3','*','*','*'],
['*','*','*','*','1','*','*'],
['*','*','1','1','3','1','*'],
['*','*','3','*','88','*','*'],
['*','*','1','1','*','*','1233']];
--------------------------------------------------
Solution:
The condition "no num circle could be generated in n*n array" is significant. The num area could be a tree!!! The problem could be transformed into the maximum path between two tree node. If writting recursive codes, two return values are required; else a accumulated dict is required.
def is_valid(nums, vis, x, y, n):
return x >= 0 and x < n and y >= 0 and y < n and nums[x][y] != '*' and vis[x][y] == 0
def dfs(nums, vis, x, y, n):
valid = is_valid(nums, vis, x, y, n)
if (valid == False):
return 0,0
vis[x][y] = 1
max_depth, max_gold = int(nums[x][y]), int(nums[x][y])
depths = []
for dx,dy in [(1,-1),(-1,-1),(1,1),(-1,1)]:
nx,ny = x+dx,y+dy
if (is_valid(nums, vis, nx, ny, n) == True):
c_depth, c_gold = dfs(nums, vis, nx, ny, n)
depths.append(c_depth)
sorted_depth = sorted(depths, reverse=True)
if len(sorted_depth) == 1:
max_depth, max_gold = int(nums[x][y])+depths[0], int(nums[x][y])+depths[0]
elif (len(sorted_depth) > 1):
max_depth, max_gold = int(nums[x][y])+depths[0], int(nums[x][y])+depths[0]+depths[1]
return max_depth, max_gold
def cal_max_gold(nums):
res = 0
n = len(nums)
vis = [[0 for j in range(n)] for i in range(n)]
for i in range(n):
for j in range(n):
max_depth, max_gold = dfs(nums, vis, i, j, n)
if (max_gold > res):
res = max_gold
return res
nums = [['*','*','4','*','*','1','*'],
['*','1','2','3','*','*','*'],
['*','1','*','3','*','*','*'],
['*','*','*','*','1','*','*'],
['*','*','1','1','3','1','*'],
['*','*','3','*','88','*','*'],
['*','*','1','1','*','*','1233']];
res = cal_max_gold(nums)
print(res)