Week4-LeetCode

1997.访问完所有房间的第一天

分析题目,可以得到两个要点:
1. 第一次到达房间i+1需要到达房间i两次
2. 到达当前房间i两次需要从nextVisit[i]再到i一次

f(i)为第一次到达房间i需要的时间,则第一次到达 i+1房间需要的时间为:

f(i + 1) = f(i) + f(i) - f(nextVisit[i])

注意: 访问房间i的那天算1天,访问房间i+11

class Solution:
    def firstDayBeenInAllRooms(self, nextVisit):
        mod = 10**9 + 7
        dp = [0] * (len(nextVisit))

        #初始化原地待一天+访问下一个房间一天
        dp[0] = 1
        for i in range(1, len(nextVisit)):
            dp[i] = (dp[i - 1] * 2 - dp[nextVisit[i-1]] + 2) % (10 ** 9 + 7)
        
        return (dp[-1] - 1) % (10 ** 9 + 7)

2684. 矩阵中移动的最大次数

  1. 动态规划
    本人采用了动态规划的思路,但代码存在问题,有一半的测试用例不通过,故找到类似思路且通过了的代码粘贴在下:
    class Solution(object):
    	def maxMoves(self, grid):
        """
        :type grid: List[List[int]]
        :rtype: int
        """
    
        # 动态规划
        	m, n = len(grid), len(grid[0])
       		dp = [[0] * n for _ in range(m)]
        	res = 0
        	for j in range(n - 2, -1, -1):
             	for i in range(m):
                	for k in i - 1, i, i+1:
                    	if 0 <= k < m and grid[k][j + 1] > grid[i][j]:
                        	dp[i][j] = max(dp[i][j], dp[k][j + 1] + 1)
        
        	for i in range(m):
            	res = max(res, dp[i][0])
        
        	return res
    

310.最小高度树

关键思路:设dist[x][y]表示节点x到节点y的距离,假定树中距离最长的两个节点为(x, y), 它们之间的距离为maxdist = dist[x][y],则树的最小高度minheight一定为 ⌈ m a x d i s t 2 ⌉ \lceil\frac{maxdist}{2}\rceil 2maxdist

  1. 广度优先搜索

    class Solution(object):
    def findMinHeightTrees(self, n, edges):
        """
        :type n: int
        :type edges: List[List[int]]
        :rtype: List[int]
        """
        if n == 1:
            return [0]
        
        # 邻接矩阵
        g = [[] for _ in range(n)]
        for x, y in edges: 
            g[x].append(y)
            g[y].append(x)
        
        # 记录父节点
        parents = [0] * n
        
        # 广度优先遍历
        def bfs(start):
            vis = [False] * n # 标记是否访问过
            vis[start] = True
            q = deque([start])  # 创建一个双端队列 并将起始元素start放入队列中
            while q:
                x = q.popleft() #
                for y in g[x]:
                    if not vis[y]:
                        vis[y] = True
                        parents[y] = x
                        q.append(y)
            return x
        x = bfs(0) # 找到与节点 0 最远的节点 x
        y = bfs(x) # 找到与节点 x 最远的节点 y
    
        path = []
        parents[x] = -1
        while y != -1:
            path.append(y)
            y = parents[y]
        m = len(path)
    
        return [path[m//2]] if m % 2 else[path[m // 2 - 1], path[m // 2]]
    
  2. 深度优先搜索

    class Solution:
    def findMinHeightTrees(self, n: int, edges: List[List[int]]) -> List[int]:
        if n == 1:
            return [0]
    
        g = [[] for _ in range(n)]
        for x, y in edges:
            g[x].append(y)
            g[y].append(x)
        parents = [0] * n
        maxDepth, node = 0, -1
    
        def dfs(x: int, pa: int, depth: int):
            nonlocal maxDepth, node
            if depth > maxDepth:
                maxDepth, node = depth, x
            parents[x] = pa
            for y in g[x]:
                if y != pa:
                    dfs(y, x, depth + 1)
        dfs(0, -1, 1)
        maxDepth = 0
        dfs(node, -1, 1)
    
        path = []
        while node != -1:
            path.append(node)
            node = parents[node]
        m = len(path)
        return [path[m // 2]] if m % 2 else [path[m // 2 - 1], path[m // 2]]
    

2952.需要添加的硬币的最小数量

  1. 贪心算法
    关键思路:
    对于正整数x,如果区间[1, x-1]内的所有金额都可取得,且x在数组中,则区间[1, 2x-1]内的所有金额也都可取得。
    贪心:每次找到不可取得的最小金额x,在数组中添加x直到找到下一个不可取得的最小整数

    def minimumAddedCoins(self, coins, target):
    	"""
    	:type coins: List[int]
    	:type target: int
    	:rtype: int
    	"""
    
    	coins.sort()
    	ans, x = 0, 1
    	index = 0
    
    	while x<= target:
        	if index < len(coins) and coins[index] <= x:
            	x += coins[index]
            	index += 1
        	else:
            	ans += 1
            	x <<= 1
    	return ans
    

8.字符串转换整数(atoi)

  1. 自动机
    关键思路:我们的程序在每个时刻有一个状态 s,每次从序列中输入一个字符 c,并根据字符 c 转移到下一个状态 s'

    INT_MAX = 2 ** 31 - 1
    INT_MIN = -2 ** 31
    
    class Automaton:
    	def __init__(self):
        	self.state = 'start'
        	self.sign = 1 # 不带符号默认为正整数
        	self.ans = 0
        	self.table = {
            	'start':['start', 'signed', 'in_number','end'],
            	'signed':['end', 'end', 'in_number', 'end'],
            	'in_number':['end', 'end', 'in_number', 'end'],
            	'end':['end', 'end', 'end', 'end'],
        	}
    
    	def get_col(self, c):
        	if c.isspace():
            	return 0
        	if c == '+' or c == '-':
            	return 1
        	if c.isdigit():
            	return 2
        	return 3
        
    	def get(self, c):
        	self.state = self.table[self.state][self.get_col(c)]
        	if self.state == 'in_number':
            	self.ans = self.ans * 10 + int(c)
            	self.ans = min(self.ans, INT_MAX) if self.sign == 1 else min(self.ans, -INT_MIN)
        	elif self.state == 'signed':
            	self.sign = 1 if c == '+' else -1
    
    class Solution(object):
    	def myAtoi(self, s):
        """
        :type s: str
        :rtype: int
        """
        	automaton = Automaton()
        	for c in s:
            	automaton.get(c)
        	return automaton.sign * automaton.ans
    

331.验证二叉树得前序序列化

关键思路:利用栈

    def isValidSerialization(self, preorder):
        """
        :type preorder: str
        :rtype: bool
        """
        stack = []
        for node in preorder.split(','):
            stack.append(node)
            while len(stack) >= 3 and stack[-1] == stack[-2] == '#' and stack[-3] !='#':
                stack.pop(), stack.pop(), stack.pop()
                stack.append('#')
        return len(stack) == 1 and stack.pop() == '#'

10.正则表达式匹配

思路:动态规划
使用dp[i][j]表示s的前i个字符与p中的前j个字符是否能够匹配。
动态规划的边界条件为f[0][0]=true,即两个空字符串是可以匹配的
从右往左扫描,s, p串是否匹配取决于最右端是否匹配、剩余的子串是否匹配

边界条件:

  1. s[i - 1] == p[j - 1]
    那么:dp[i][j] = dp[i - 1][j - 1]

  2. s[i - 1] != p[j - 1]

    1. p[i - 1] == '*' and s[i - 1] == p[j - 2] ,关于and的第二个条件,可以展开以下讨论:
      • p[j - 1]*可以让p[j - 2]p串中消失
        那么dp[i][j] = dp[i][j - 2]
      • p[j-2] 重复1次 (这个时候p的最后一个字符和s的倒数第二个字符是匹配的)
        那么 dp[i][j] = dp[i -1][j -2]
      • p[j - 2]重复 ≥ \geq 2
        那么dp[i][j] = dp[i-1][j]
  3. p 为空串,s 不为空串,肯定不匹配。
    s 为空串,但 p 不为空串,要想匹配,只可能是右端是星号,它干掉一个字符后,把 p 变为空串。
    s、p 都为空串,肯定匹配。

class Solution:
    def isMatch(self, s, p):
        if s is None or p is None:
            return False
    
        sLen, pLen = len(s), len(p)
    
        dp = [[False] * (pLen + 1) for _ in range(sLen + 1)]
    
    # base case
        dp[0][0] = True
        for j in range(1, pLen + 1):
            if p[j - 1] == "*":
                dp[0][j] = dp[0][j - 2]
    
    # 迭代
        for i in range(1, sLen + 1):
            for j in range(1, pLen + 1):
                if s[i - 1] == p[j - 1] or p[j - 1] == ".":
                    dp[i][j] = dp[i - 1][j - 1]
                elif p[j - 1] == "*":
                    if s[i - 1] == p[j - 2] or p[j - 2] == ".":
                        dp[i][j] = dp[i][j - 2] or dp[i - 1][j - 2] or dp[i - 1][j]
                    else:
                        dp[i][j] = dp[i][j - 2]
    
        return dp[sLen][pLen]
  • 26
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值