leetcode刷题 396~
题目396题
旋转函数
给定一个长度为 n 的整数数组 A 。
假设 Bk 是数组 A 顺时针旋转 k 个位置后的数组,我们定义 A 的“旋转函数” F 为:
F(k) = 0 * Bk[0] + 1 * Bk[1] + ... + (n-1) * Bk[n-1]。
计算F(0), F(1), ..., F(n-1)中的最大值。
思路实现
class Solution: def maxRotateFunction(self, A: List[int]) -> int: if not A: return 0 s,f0, l = 0, 0, len(A) for i in range(l): f0 += i * A[i] s += A[i] result = float("-inf") for i in range(l-1, -1, -1): f0 = f0 - l*A[i] + s result = max(result, f0) return result
题目397题
整数替换
思路
1.动态规划:居然超时了
2.记忆化递归:
@lru_cache(None)
:Python
标准库,用于缓存
实现
1. class Solution: def integerReplacement(self, n: int) -> int: if n == 1: return 0 dp = [0 for _ in range(n+4)] dp[1],dp[2] = 0,1 i = 4 while dp[n] == 0: if i % 2 == 0: dp[i] = dp[i//2] + 1 i -= 1 elif i % 2 == 1: dp[i] = min(dp[i+1],dp[i-1]) + 1 i += 3 return dp[n] 2. class Solution: def integerReplacement(self, n: int) -> int: @lru_cache(None) def dfs(n): if n==1: return 0 ans=0 if n&1: ans+=1+min(dfs(n+1),dfs(n-1)) else: ans+=1+dfs(n//2) return ans return dfs(n)
题目398题
随机数索引
思路
1.字典:在初始化中建立字典,键为元素的值,值为元素索引组成的数组
2.蓄水池抽样
实现
class Solution: def __init__(self, nums: List[int]): self.dic =dict() for idx in range(len(nums)): self.dic.setdefault(nums[idx], []).append(idx) def pick(self, target: int) -> int: temp = self.dic[target] ran = random.randint(0,len(temp)-1) return temp[ran]
2.
题目399题
除法求值
给出方程式 A / B = k, 其中 A 和 B 均为用字符串表示的变量, k 是一个浮点型数字。根据已知方程式求解问题,并返回计算结果。如果结果不存在,则返回 -1.0。
输入总是有效的。你可以假设除法运算中不会出现除数为 0 的情况,且不存在任何矛盾的结果。
思路
深度优先遍历:先构造图,然后深度优先遍历
实现
class Solution: def calcEquation(self, equations: List[List[str]], values: List[float], queries: List[List[str]]) -> List[float]: graph = {} for (x, y), v in zip(equations, values): if x in graph: graph[x][y] = v else: graph[x] = {y: v} if y in graph: graph[y][x] = 1/v else: graph[y] = {x: 1/v} def dfs(qs, qt)->int: if qs not in graph: return -1 if qs == qt: return 1 for node in graph[qs].keys(): if node == qt: return graph[qs][node] elif node not in visited: visited.add(node) value = dfs(node,qt) if value != -1: return graph[qs][node]*value return -1 result = [] for qs, qt in queries: visited = set() result.append(dfs(qs, qt)) return result
题目400题
第N个数字
在无限的整数序列 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, ...中找到第 n 个数字。
思路
首先确定这个数的长度,根据长度来确实结束时的数的大小,然后判断是这个数字的第几位,最后返回结果
实现
class Solution: def findNthDigit(self, n: int) -> int: wei= 1 index = wei * 9 * (10**(wei-1)) while n > index: n -= index wei += 1 index = wei * 9 * (10**(wei-1)) num = (10**(wei-1)) + (n-1)//wei remain = (n-1)%wei numstr = str(num) return numstr[remain]
题目401题
二进制手表
二进制手表顶部有 4 个 LED 代表 小时(0-11),底部的 6 个 LED 代表 分钟(0-59)。每个 LED 代表一个 0 或 1,最低位在右侧。
示例:
输入: n = 1
返回: ["1:00", "2:00", "4:00", "8:00", "0:01", "0:02", "0:04", "0:08", "0:16", "0:32"]
思路
分别计算小时和分钟
实现
class Solution: def readBinaryWatch(self, num: int) -> List[str]: hour_result = [] min_result = [] def dfs(wei,num,res,sigh): if wei == 0 and num ==0: if sigh == True: if res < 12: hour_result.append(res) else: if res <60: min_result.append(res) elif wei <= 0: return 0 for i in range(2): if i == 0: dfs(wei-1,num,res,sigh) else: dfs(wei-1,num-1,res+2**(wei-1),sigh) result = [] for hour in range(num+1): hour_result = [] min_result = [] dfs(4,hour,0,True) dfs(6,num-hour,0,False) for i in hour_result: for j in min_result: temp = str(i) + ":" temp += str(j) if j>=10 else "0"+str(j) result.append(temp) return result
题目402题
移掉K位数字
给定一个以字符串表示的非负整数 num,移除这个数中的 k 位数字,使得剩下的数字最小。
注意:
num 的长度小于 10002 且 ≥ k。
num 不会包含任何前导零。
思路
给定一个数字序列 [D1D2D3…Dn] ,如果数字 D2 < D1,则我们应该删除左邻居D1,以获得最小结果。
实现
class Solution: def removeKdigits(self, num: str, k: int) -> str: result = [] for i in num: while result and k and result[-1] > i: result.pop() k -= 1 result.append(i) result = result[:-k] if k else result return "".join(result).lstrip('0') or "0"
题目404题
左叶子之和
计算给定二叉树的所有左叶子之和。
思路实现
class Solution: def sumOfLeftLeaves(self, root: TreeNode) -> int: def sumofleavse(node, sigh): val = 0 if not node: return val if node.left: val += sumofleavse(node.left, True) if node.right: val += sumofleavse(node.right, False) if not node.left and not node.right and sigh: val += node.val return val return sumofleavse(root,False)
题目405题
数字转换为十六进制
给定一个整数,编写一个算法将这个数转换为十六进制数。对于负整数,我们通常使用 补码运算 方法。
思路
主要是理解补码:
num = (abs(num) ^ ((2 ** 32) - 1)) + 1
实现
class Solution: def toHex(self, num: int) -> str: hexnum = "0123456789abcdef" def get(num): result = "" while num != 0: i = num % 16 result = hexnum[i] + result num = num // 16 return result if num < 0: num = (abs(num) ^ ((2 ** 32) - 1)) + 1 elif num ==0: return "0" return get(num)
题目406题
根据身高重建队列
假设有打乱顺序的一群人站成一个队列。 每个人由一个整数对(h, k)表示,其中h是这个人的身高,k是排在这个人前面且身高大于或等于h的人数。 编写一个算法来重建这个队列。
注意:
总人数少于1100人。
示例
输入:
[[7,0], [4,4], [7,1], [5,0], [6,1], [5,2]]
输出:
[[5,0], [7,0], [5,2], [6,1], [4,4], [7,1]]
思路
没有做出来,查看解答后发现是利用的贪心算法,利用矮的人相对于高的人是看不见的:因为k的值是前面比自己高或等高的人的个数。先处理高的人,满足k的条件后,再处理矮的人是不会破坏这个条件的。
算法:
- 排序:
- 按高度降序排列。
- 在同一高度的人中,按
k
值的升序排列。
- 逐个地把它们放在输出队列中,索引等于它们的
k
值。 - 返回输出队列
实现
class Solution: def reconstructQueue(self, people: List[List[int]]) -> List[List[int]]: people = sorted(people, key = lambda x: (-x[0], x[1])) result =[] for i in people: result.insert(i[1],i) return result
题目395题
最长回文串
给定一个包含大写字母和小写字母的字符串,找到通过这些字母构造成的最长的回文串。
在构造过程中,请注意区分大小写。比如 "Aa"
不能当做一个回文字符串。
思路实现
class Solution: def longestPalindrome(self, s: str) -> int: dic = dict() for i in s: dic[i] = dic.get(i,0) + 1 result,sign = 0, 0 for i in dic: num = dic[i]//2 if num >= 1: result += num*2 if dic[i]%2 == 1: sign = 1 return result+sign
题目412题
FizzBuzz
写一个程序,输出从 1 到 n 数字的字符串表示。
1. 如果 n 是3的倍数,输出“Fizz”;
2. 如果 n 是5的倍数,输出“Buzz”;
3.如果 n 同时是3和5的倍数,输出 “FizzBuzz”。
思路实现
class Solution: def fizzBuzz(self, n: int) -> List[str]: result = ["" for _ in range(n)] for i in range(n): temp = i+1 if temp%3 == 0: result[i] += "Fizz" if temp%5 == 0: result[i] += "Buzz" if result[i] == "": result[i] += str(temp) return result
题目414题
第三大的数
思路实现
class Solution: def thirdMax(self, nums: List[int]) -> int: first, second, third = float("-inf"), float("-inf"),float("-inf") for num in nums: if num > first: third,second = second,first first = num elif num == first: continue elif num > second: third = second second = num elif num == second: continue elif num > third: third = num if third != float("-inf"): return third else: return first
题目395题
字符串相加
思路实现
class Solution: def addStrings(self, num1: str, num2: str) -> str: index1, index2, add = len(num1)-1, len(num2)-1, 0 result = "" while index1 >= 0 or index2 >=0 or add != 0: x = int(num1[index1]) if index1 >= 0 else 0 y = int(num2[index2]) if index2 >= 0 else 0 temp = x + y + add result = str(temp%10) + result add = temp//10 index1 -= 1 index2 -= 1 return result
题目417题
太平洋大西洋水流问题
给定一个 m x n 的非负整数矩阵来表示一片大陆上各个单元格的高度。“太平洋”处于大陆的左边界和上边界,而“大西洋”处于大陆的右边界和下边界。
规定水流只能按照上、下、左、右四个方向流动,且只能从高到低或者在同等高度上流动。
请找出那些水流既可以流动到“太平洋”,又能流动到“大西洋”的陆地单元的坐标。
思路
深度优先遍历:最开始的时候期望正向流动来解决问题,但是遇到了许多问题:1.从不同的位置去访问同一个位置可能结果不同2.无法控制是否访问过(如果访问过就不再访问会漏解)
因此只能使用反向流动的方式来解决问题。以太平洋为例,从太平洋的边界向内遍历(按题目要求需要大于等于高度),如果能够遍历到说明在太平洋的界内;大西洋同理。大西洋和太平洋的交集就是最后的结果。
实现
class Solution: def pacificAtlantic(self, matrix: List[List[int]]) -> List[List[int]]: if not matrix or len(matrix) == 0: return [] row, col = len(matrix), len(matrix[0]) visied = [[0 for _ in range(col)] for _ in range(row)] a = [[0 for _ in range(col)] for _ in range(row)] p = [[0 for _ in range(col)] for _ in range(row)] move = [(0,1),(0,-1),(1,0),(-1,0)] result = list() def dfs(i, j,temp): temp[i][j] = 1 for x, y in move: ni,nj = i + x, j+y if 0<= ni < row and 0<= nj < col and matrix[i][j] <= matrix[ni][nj] and temp[ni][nj] != 1: dfs(ni,nj,temp) for i in range(col): dfs(0, i, p) dfs(row-1, i, a) for i in range(row): dfs(i, 0 , p) dfs(i, col-1, a) for i in range(row): for j in range(col): if a[i][j] * p[i][j]: result.append([i,j]) return result
题目416题
分割等和子集
给定一个只包含正整数的非空数组。是否可以将这个数组分割成两个子集,使得两个子集的元素和相等。
注意:
每个数组中的元素不会超过 100
数组的大小不会超过 200
示例 1:
输入: [1, 5, 11, 5]
输出: true
解释: 数组可以分割成 [1, 5, 5] 和 [11].
思路
动态规划:背包问题,详细见背包问题九讲。
实现
class Solution: def canPartition(self, nums: List[int]) -> bool: total = sum(nums) if total%2 !=0: return False half = total//2 dp = [[False for _ in range(half+1)] for _ in range(len(nums))] for i in range(len(nums)): for j in range(0,half+1): if nums[i] == j: dp[i][j] = True continue if nums[i] < j: dp[i][j] = dp[i-1][j] or dp[i-1][j-nums[i]] return dp[-1][half] class Solution: def canPartition(self, nums: List[int]) -> bool: total = sum(nums) if total%2 !=0: return False half = total//2 dp = [False for _ in range(half+1)] for i in range(len(nums)): for j in range(half,-1,-1): if nums[i] == j: dp[j] = True continue if nums[i] < j: dp[j] = dp[j] or dp[j-nums[i]] print(dp) return dp[half]
题目419题
甲板上的战舰
思路
1.深度优先遍历
2.在进阶中要求扫描一次,且空间复杂度为O(n),因此只计算战舰头,若遇到x,其左边或者上面有x,则不计算
实现
class Solution: def countBattleships(self, board: List[List[str]]) -> int: count = 0 row, col = len(board), len(board[0]) def dfs(i,j): if board[i][j] == ".": return elif board[i][j] == "!": return elif board[i][j] == "X": board[i][j] = "!" if 0<= i+1 < row and 0<= j < col and board[i+1][j] == "X": dfs(i+1,j) elif 0<= i < row and 0<= j+1 < col and board[i][j+1] == "X": dfs(i,j+1) else: nonlocal count count += 1 for i in range(row): for j in range(col): dfs(i,j) return count class Solution: def countBattleships(self, board: List[List[str]]) -> int: count = 0 row, col = len(board), len(board[0]) for i in range(row): for j in range(col): if board[i][j] == ".": continue if i>0 and board[i-1][j] == "X": continue if j>0 and board[i][j-1] == "X": continue count += 1 return count