Leetcode Path with Maximum Gold

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)

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值