Contents
- 1 3月1日:用队列实现栈
- 2 3月2日:反转链表
- 3 3月3日:合并排序的数组
- 4 3月4日:腐烂的橘子🍊
- 5 3月5日:分糖果II
- 6 3月6日:和为s的连续正数序列
- 7 3月7日:队列的最大值
- 8 3月8日:零钱兑换
- 9 3月9日:买卖股票的最佳时机
- 10 3月10日:二叉树的直径
- 11 3月11日:将数组分成和相等的三个部分
- 12 3月12日:字符串的最大公因子
- 13 3月13日:多数元素
- 14 3月14日:最长上升子序列
- 15 3月15日:岛屿的最大面积
- 16 3月16日:字符串压缩
- 17 3月17日:拼写单词
- 18 3月18日:矩形重叠
- 19 3月19日:最长回文串
- 20 3月20日:最小的k个数
- 21 3月21日:水壶问题
- 22 3月22日:使数组唯一的最小增量
- 23 3月23日:链表的中间结点
- 24 3月24日:按摩师
- 25 3月25日:三维形体的表面积
- 26 3月26日:车的可用捕获量
- 27 3月27日:卡牌分组
- 28 3月28日:单词的压缩编码
- 29 3月29日:地图分析
- 30 3月30日:圆圈中最后剩下的数字(约瑟夫环)
- 31 3月31日:排序树组
3月1日:用队列实现栈
使用队列实现栈的下列操作:
push(x) — 元素 x 入栈
pop() — 移除栈顶元素
top() — 获取栈顶元素
empty() — 返回栈是否为空
思路:
见代码。。。
代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
def __init__(self): self.data = [] def push(self, x: int) -> None: self.data.append(x) def pop(self) -> int: ans = self.data[-1] self.data = self.data[:-1] return ans def top(self) -> int: return self.data[-1] # 取最后一个元素并返回 def empty(self) -> bool: return len(self.data) == 0 |
3月2日:反转链表
反转一个单链表。
示例:
输入: 1->2->3->4->5->NULL
输出: 5->4->3->2->1->NULL
思路:
使用两个指针,一个在原链表中移动,另一个插入到新链表中。
代码: 递归的方法:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
class Solution: def helper(self, node: ListNode, next: ListNode) -> ListNode: if not node: self.ans = next return else: tmp = node.next node.next = next self.helper(tmp, node) def reverseList(self, head: ListNode) -> ListNode: self.ans = None if not head: return None self.helper(head, None) return self.ans |
网友给的迭代的方法:
1 2 3 4 5 6 7 |
class Solution: def reverseList(self, head): p, rev = head, None while p: rev, rev.next, p = p, rev, p.next return rev |
3月3日:合并排序的数组
给定两个排序后的数组 A 和 B,其中 A 的末端有足够的缓冲空间容纳 B。 编写一个方法,将 B 合并入 A 并排序。
初始化 A 和 B 的元素数量分别为 m 和 n。
示例:
输入:
A = [1,2,3,0,0,0], m = 3
B = [2,5,6], n = 3
输出: [1,2,2,3,5,6]
思路:
将B中的元素用insert
插入到A中即可。注意A为空时可能会越界异常。
代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
class Solution: def merge(self, A: List[int], m: int, B: List[int], n: int) -> None: if m == 0: A[:] = B[:] return temp = A[:m] i = 0 j = 0 for j in range(n): while temp[i] < B[j]: i += 1 if i >= len(temp): break temp.insert(i, B[j]) A[:] = temp[:] |
3月4日:腐烂的橘子🍊
在给定的网格中,每个单元格可以有以下三个值之一:
值 0 代表空单元格;
值 1 代表新鲜橘子;
值 2 代表腐烂的橘子。
每分钟,任何与腐烂的橘子(在 4 个正方向上)相邻的新鲜橘子都会腐烂。
返回直到单元格中没有新鲜橘子为止所必须经过的最小分钟数。如果不可能,返回 -1。
示例 1:
输入:[[2,1,1],[1,1,0],[0,1,1]]
输出:4
示例 2:
输入:[[2,1,1],[0,1,1],[1,0,1]]
输出:-1
解释:左下角的橘子(第 2 行, 第 0 列)永远不会腐烂,因为腐烂只会发生在 4 个正向上。
示例 3:
输入:[[0,2]]
输出:0
解释:因为 0 分钟时已经没有新鲜橘子了,所以答案就是 0 。
思路:
BFS,维护一个(滚动的)列表rottings
,记录每一轮新腐烂的橘子。
每一轮中,rottings
中的所有橘子🍊,都会尝试腐烂周围的橘子。如果某一轮不能腐烂新的橘子,则结束循环。
结束循环后,如果还有未腐烂的橘子,则返回-1
,否则返回轮数ans
。
代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 |
class Solution: def orangesRotting(self, grid: List[List[int]]) -> int: arounds = [(-1, 0), (1, 0), (0, -1), (0, 1)] # 四个方向 if len(grid) == 0: return 0 rottings = [] for i, line in enumerate(grid): for j, row in enumerate(line): if row == 2: rottings.append((i,j)) # 刚开始时腐烂的橘子 ans = 0 new_rotting = [] def rot(x, y): if x < 0 or y < 0 or x >= len(grid) or y >= len(grid[0]): return False if grid[x][y] == 1: grid[x][y] = 2 # 成功腐烂新鲜的橘子,返回True new_rotting.append((x,y)) return True return False while True: new_rotting.clear() has_new_rotting = False # 这一轮是否腐烂了新的橘子 for i, j in rottings: for i1, j1 in arounds: if rot(i + i1, j + j1): has_new_rotting = True if not has_new_rotting: for line in grid: if line.count(1) != 0: return -1 return ans rottings = new_rotting.copy() ans += 1 |
3月5日:分糖果II
排排坐,分糖果。
我们买了一些糖果 candies,打算把它们分给排好队的 n = num_people 个小朋友。
给第一个小朋友 1 颗糖果,第二个小朋友 2 颗,依此类推,直到给最后一个小朋友 n 颗糖果。
然后,我们再回到队伍的起点,给第一个小朋友 n + 1 颗糖果,第二个小朋友 n + 2 颗,依此类推,直到给最后一个小朋友 2 * n 颗糖果。
重复上述过程(每次都比上一次多给出一颗糖果,当到达队伍终点后再次从队伍起点开始),直到我们分完所有的糖果。注意,就算我们手中的剩下糖果数不够(不比前一次发出的糖果多),这些糖果也会全部发给当前的小朋友。
返回一个长度为 num_people、元素之和为 candies 的数组,以表示糖果的最终分发情况(即 ans[i] 表示第 i 个小朋友分到的糖果数)。
示例 1:
输入:candies = 7, num_people = 4
输出:[1,2,3,1]
解释:
第一次,ans[0] += 1,数组变为 [1,0,0,0]。
第二次,ans1 += 2,数组变为 [1,2,0,0]。
第三次,ans[2] += 3,数组变为 [1,2,3,0]。
第四次,ans[3] += 1(因为此时只剩下 1 颗糖果),最终数组变为 [1,2,3,1]。
示例 2:
输入:candies = 10, num_people = 3
输出:[5,2,3]
解释:
第一次,ans[0] += 1,数组变为 [1,0,0]。
第二次,ans1 += 2,数组变为 [1,2,0]。
第三次,ans[2] += 3,数组变为 [1,2,3]。
第四次,ans[0] += 4,最终数组变为 [5,2,3]。
思路:
i
表示第几个小朋友,j
表示分几颗糖果。
代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
class Solution: def distributeCandies(self, candies: int, num_people: int) -> List[int]: ans = [0 for i in range(num_people)] i = 0 # 第一个小朋友 j = 1 # 分几颗糖 while candies >= j: candies -= j ans[i] += j j += 1 i = (i + 1) % (num_people) i = (i + 1) % (num_people) if candies: ans[i-1] += candies return ans |
3月6日:和为s的连续正数序列
输入一个正整数 target ,输出所有和为 target 的连续正整数序列(至少含有两个数)。
序列内的数字由小到大排列,不同序列按照首个数字从小到大排列。
示例 1:
输入:target = 9
输出:[[2,3,4],[4,5]]
示例 2:
输入:target = 15
输出:[[1,2,3,4,5],[4,5,6],[7,8]]
思路:
等差数列的和,target
=平均值 × 序列长度length
。
序列长度一定为target × 2
的因子并且大于1,遍历target × 2
的因子寻找序列长度即可。
序列越长的首个数字越小。
代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
class Solution: def findContinuousSequence(self, target: int) -> List[List[int]]: s = target * 2 # (a + b) * (b-a+1) / 2 ans = [] for length in range(int(math.sqrt(s)), 1, -1): if s % length == 0: ave = (s // length + 1) // 2 # 平均值 start = ave - length // 2 # 第一个数 line = [i for i in range(start, length + start)] if sum(line) == target: # 反向判断一下是否正确 ans.append(line) return ans |
3月7日:队列的最大值
请定义一个队列并实现函数 max_value 得到队列里的最大值,要求函数max_value、push_back 和 pop_front 的均摊时间复杂度都是O(1)。
若队列为空,pop_front 和 max_value 需要返回 -1
示例 1:
输入:
[“MaxQueue”,”push_back”,”push_back”,”max_value”,”pop_front”,”max_value”]
[[],1,[2],[],[],[]]
输出: [null,null,null,2,1,2]
示例 2:
输入:
[“MaxQueue”,”pop_front”,”max_value”]
[[],[],[]]
输出: [null,-1,-1]
思路:
维护一个主队列q
和一个辅助队列helper
。主队列就是正常的队列,负责push
和pop
;辅助队列helper
是一个双端队列。
push_back
操作时,如果新的value
大于helper
队尾的元素,则一直弹出helper
队尾的元素。之后再将value
加到helper
队尾。
pop_front
操作时,如果q
的对头元素value
等于helper
的对头元素,则弹出helper
对头的元素。
max_value
操作时,如果辅助队列不为空,则返回辅助队列对头的元素。
例如:[3, 1, 2, 4]
初始,q=[]
, helper=[]
。
入队列,q=[3]
, helper=[3]
;
入队列,q=[3, 1]
, helper=[3, 1]
;
入队列,q=[3, 1, 2]
, helper=[3, 2]
;
入队列,q=[3, 1, 2, 4]
, helper=[4]
;
出队列,q=[1, 2, 4]
, helper=[4]
;
出队列,q=[2, 4]
, helper=[4]
;
出队列,q=[4]
, helper=[4]
;
出队列,q=[]
, helper=[]
;
代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 |
class MaxQueue: def __init__(self): self.q = [] self.helper = [] def max_value(self) -> int: if len(self.helper) == 0: return -1 return self.helper[0] def push_back(self, value: int) -> None: self.q.append(value) while len(self.helper) > 0 and value > self.helper[-1]: self.helper = self.helper[:-1] # pop_right self.helper.append(value) def pop_front(self) -> int: if len(self.q) == 0: return -1 q0 = self.q[0] self.q = self.q[1:] # pop_left if len(self.helper) > 0 and self.helper[0] == q0: self.helper = self.helper[1:] # pop_left return q0 |
3月8日:零钱兑换
给定不同面额的硬币 coins 和一个总金额 amount。编写一个函数来计算可以凑成总金额所需的最少的硬币个数。如果没有任何一种硬币组合能组成总金额,返回 -1。
示例 1:
输入: coins = [1, 2, 5], amount = 11
输出: 3
解释: 11 = 5 + 5 + 1
示例 2:
输入: coins = [2], amount = 3
输出: -1
思路:
背包🎒问题。
1. 如果已知所有amount - coin
所需的最少硬币个数,那么amount
所需的最少硬币个数为 min(coinChange(amount - coin_i) + 1)
,coin_i∈coins。
2. coinChange[0] = 0
。
代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
class Solution: def coinChange(self, coins: List[int], amount: int) -> int: ans = [-1 for i in range(amount + 1)] ans[0] = 0 for i in range(1, amount+1): ansi = 99999999 if ans[i] == -1: for coin in coins: left = i - coin if left >= 0: if ans[left] != -1: ansi = min(ansi, ans[left]+1) ansi = -1 if ansi == 99999999 else ansi ans[i] = ansi return ans[amount] |
3月9日:买卖股票的最佳时机
给定一个数组,它的第 i 个元素是一支给定股票第 i 天的价格。
如果你最多只允许完成一笔交易(即买入和卖出一支股票),设计一个算法来计算你所能获取的最大利润。
注意你不能在买入股票前卖出股票。
示例 1:
输入: [7,1,5,3,6,4]
输出: 5
解释: 在第 2 天(股票价格 = 1)的时候买入,在第 5 天(股票价格 = 6)的时候卖出,最大利润 = 6-1 = 5 。
注意利润不能是 7-1 = 6, 因为卖出价格需要大于买入价格。
示例 2:
输入: [7,6,4,3,1]
输出: 0
解释: 在这种情况下, 没有交易完成, 所以最大利润为 0。
思路:
今天国际原油跌了近30%,美股熔断,这道题来的真是时候啊❄️。。。
使用双指针,i
表示买入时的下标,j
表示卖出时的下标,ans
存放全局利润最大值。如果卖出价格<=买入价格
,则将买入价格
更新为卖出价格
。否则j
不断向后移,如果prices[j]-prices[i]
大于ans
,则更新全局的ans
。
代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
class Solution: def maxProfit(self, prices: List[int]) -> int: i, j = 0, 1 l = len(prices) ans = 0 while True: if j >= l: return ans buy = prices[i] sell = prices[j] if sell <= buy: # 卖出价格小于买入价格,则以卖出价格买入 i = j j = j + 1 else: ans = max(ans, sell - buy) # 如果有更大利润则更新利润 j += 1 return ans |
3月10日:二叉树的直径
给定一棵二叉树,你需要计算它的直径长度。一棵二叉树的直径长度是任意两个结点路径长度中的最大值。这条路径可能穿过根结点。
示例 :
1 2 3 4 5 6 |
1 / \ 2 3 / \ 4 5 |
返回 3, 它的长度是路径 [4,2,1,3] 或者 [5,2,1,3]。
思路:
有点像第21场双周赛的第4题,不过稍微简单一点。。
dfs。遍历时计算每个结点向左走的路径最大值
,向右走的路径最大值
,以及直径
。
其中 向左走的路径最大值
= max(左孩子向左走的路径最大值
,左孩子向右走的路径最大值
) + 1。
向右走的路径最大值
= max(右孩子向左走的路径最大值
,右孩子向右走的路径最大值
) + 1。
直径
= max(左孩子的直径
,右孩子的直径
,向左走的路径最大值
+ 向右走的路径最大值
)。
代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
class Solution: def dfs(self, root: TreeNode): to_left, to_right, diameter = 0, 0, 0 if root.left: left_to_left, left_to_right, left_diameter = self.dfs(root.left) to_left = max(left_to_left, left_to_right) + 1 diameter = max(diameter, left_diameter) if root.right: right_to_left, right_to_right, right_diameter = self.dfs(root.right) to_right = max(right_to_left, right_to_right) + 1 diameter = max(diameter, right_diameter) diameter = max(diameter, to_left + to_right) return to_left, to_right, diameter def diameterOfBinaryTree(self, root: TreeNode) -> int: if not root: return 0 to_left, to_right, diameter = self.dfs(root) return diameter |
3月11日:将数组分成和相等的三个部分
给你一个整数数组 A,只有可以将其划分为三个和相等的非空部分时才返回 true,否则返回 false。
形式上,如果可以找出索引 i+1 < j 且满足 (A[0] + A1 + … + A[i] == A[i+1] + A[i+2] + … + A[j-1] == A[j] + A[j-1] + … + A[A.length – 1]) 就可以将数组三等分。
示例 1:
输出:[0,2,1,-6,6,-7,9,1,2,0,1]
输出:true
解释:0 + 2 + 1 = -6 + 6 – 7 + 9 + 1 = 2 + 0 + 1
示例 2:
输入:[0,2,1,-6,6,7,9,-1,2,0,1]
输出:false
示例 3:
输入:[3,3,6,5,-2,2,5,1,-9,4]
输出:true
解释:3 + 3 = 6 = 5 – 2 + 2 + 5 + 1 – 9 + 4
思路:
先计算sum(A)
,如果sum(A)
不能被3整除,则直接返回False
。
令ave = sum(A) // 3
,也就是每一段的和都为ave
。
遍历数组A
并求累计和,如果累计和为ave
则count += 1
。
当count == 3
时,说明已经有三段和为ave
了,未使用的元素和须为0才返回True
。
遍历结束后,当count == 3
且没有多余数字时返回True
。
代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
class Solution: def canThreePartsEqualSum(self, A: List[int]) -> bool: total = sum(A) # 不能被3整除直接返回False if total % 3 != 0: return False ave = total // 3 # 每段的值 # 0呢 ans = False sums, count = 0, 0 for i, num in enumerate(A): sums += num if count == 3: # 如果已经有三段和为ave了,那么之后的和必须为0 return sum(A[i:]) == 0 if sums == ave: count += 1 sums = 0 return count == 3 and sums == 0 # 三段并且没有多余的数字 |
3月12日:字符串的最大公因子
对于字符串 S 和 T,只有在 S = T + … + T(T 与自身连接 1 次或多次)时,我们才认定 “T 能除尽 S”。
返回最长字符串 X,要求满足 X 能除尽 str1 且 X 能除尽 str2。
示例 1:
输入:str1 = “ABCABC”, str2 = “ABC”
输出:”ABC”
示例 2:
输入:str1 = “ABABAB”, str2 = “ABAB”
输出:”AB”
示例 3:
输入:str1 = “LEET”, str2 = “CODE”
输出:””
思路:
类似于辗转相减法,如果两字符串相同,则最大公因子为任何一个字符串
。
假设str1
长度大于str2
,计算str1-str2
,然后再递归gcdOfStrings(str1-str2, str2)
。其中字符串相减定义为从开头减去,如果str1
不以str2
开头,则直接返回空字符串
。
代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
class Solution: def gcdOfStrings(self, str1: str, str2: str) -> str: if len(str1) == 0 or len(str2) == 0: return '' # 两字符串都为空 if len(str1) == len(str2): if str1 != str2: # 两字符串长度相同,但内容不相同 return '' else: return str1 if len(str1) < len(str2): str1, str2 = str2, str1 # 保证str1的长度更长 l2 = len(str2) # 做"减法" if not str1.startswith(str2): return '' delta = str1[l2:] return self.gcdOfStrings(str2 ,delta) |
3月13日:多数元素
给定一个大小为 n 的数组,找到其中的多数元素。多数元素是指在数组中出现次数大于 ⌊ n/2 ⌋ 的元素。
你可以假设数组是非空的,并且给定的数组总是存在多数元素。
示例 1:
输入: [3,2,3]
输出: 3
示例 2:
输入: [2,2,1,1,1,2,2]
输出: 2
思路:
方法一:用一个字典(哈希表)记录每个数出现的次数,如果大于n//2
则返回该数。
方法二:网友给出的摩尔投票法
:从第一个数开始count=1
,遇到相同的就加1,遇到不同的就减1,减到0就重新换个数开始计数,总能找到最多的那个。
代码:
方法一
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
class Solution: def majorityElement(self, nums: List[int]) -> int: helper = {} n = len(nums) // 2 if n == 0: return nums[0] for num in nums: if num in helper: helper[num] += 1 if helper[num] > n: return num else: helper[num] = 1 |
方法二
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
class Solution: def majorityElement(self, nums: List[int]) -> int: count = 1 ans = nums[0] for i, num in enumerate(nums[1:]): if num == ans: count += 1 else: count -= 1 if not count: ans = nums[i+2] return ans |
3月14日:最长上升子序列
给定一个无序的整数数组,找到其中最长上升子序列的长度。
示例:
输入: [10,9,2,5,3,7,101,18]
输出: 4
解释: 最长的上升子序列是 [2,3,7,101],它的长度是 4。
说明:
可能会有多种最长上升子序列的组合,你只需要输出对应的长度即可。
你算法的时间复杂度应该为 O(n2) 。
进阶: 你能将算法的时间复杂度降低到 O(n log n) 吗?
思路:
方法一:用一个辅助数组orders
记录以每个数为最大的数字时,最长上升子序列的长度。如示例中[10,9,2,5,3,7,101,18]
对应的orders=[1,1,1,2,1,3,4,4]
。
初始状态orders
全为1
,统计nums
中某个数字之前所有比它小的数字的orders
的最大值 + 1即为order[i]
新的值。复杂度为O(n^2)
。
方法二:维护一个升序的
结果数组results
。如果num
大于结果数组中的所有元素,就将num
插入到结果数组的最后。否则用num
替换results
中第一个大于等于num
的数。
最终results
的长度即为结果。复杂度为O(nlogn)
。
代码:
方法一:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
class Solution: def lengthOfLIS(self, nums: List[int]) -> int: n = len(nums) if not n: return 0 orders = [1 for i in range(n)] # 以nums[i]为最大s\数的最长上升子序列长度 ans = 1 i = 0 for i in range(n-1): if nums[i+1] > nums[i]: orders[i+1] = 2 ans = 2 break for i in range(i+2, n): order_i = 1 for j in range(i): if nums[j] < nums[i]: order_i = max(order_i, orders[j]+1) orders[i] = order_i ans = max(ans, order_i) return ans |
方法二:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
class Solution: def lengthOfLIS(self, nums: List[int]) -> int: if len(nums) == 0: return 0 results = [] for num in nums: if len(results) == 0 or num > results[-1]: results.append(num) else: for i, re in enumerate(results): if re >= num: results[i] = num break print(results) return len(results) |
3月15日:岛屿的最大面积
给定一个包含了一些 0 和 1的非空二维数组 grid , 一个 岛屿 是由四个方向 (水平或垂直) 的 1 (代表土地) 构成的组合。你可以假设二维矩阵的四个边缘都被水包围着。
找到给定的二维数组中最大的岛屿面积。(如果没有岛屿,则返回面积为0。)
示例 1:
[[0,0,1,0,0,0,0,1,0,0,0,0,0],
[0,0,0,0,0,0,0,1,1,1,0,0,0],
[0,1,1,0,1,0,0,0,0,0,0,0,0],
[0,1,0,0,1,1,0,0,1,0,1,0,0],
[0,1,0,0,1,1,0,0,1,1,1,0,0],
[0,0,0,0,0,0,0,0,0,0,1,0,0],
[0,0,0,0,0,0,0,1,1,1,0,0,0],
[0,0,0,0,0,0,0,1,1,0,0,0,0]]
对于上面这个给定矩阵应返回 6。注意答案不应该是11,因为岛屿只能包含水平或垂直的四个方向的‘1’。
示例 2:
[[0,0,0,0,0,0,0,0]]
对于上面这个给定的矩阵, 返回 0。
思路:
经典dfs。遍历整个矩阵,从任意岛屿
的任意位置
开始dfs,搜索过程中累计该岛屿的面积,并将该岛屿搜索过的位置都置为水
。
代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 |
class Solution: def maxAreaOfIsland(self, grid: List[List[int]]) -> int: ans = 0 m = len(grid) if not m: return 0 n = len(grid[0]) iland_count = 0 # 记录当前遍历岛的面积 def dfs(i, j): nonlocal m, n, iland_count, ans if i < 0 or j < 0 or i >= m or j >= n: return if grid[i][j] == 0: return iland_count += 1 ans = max(ans, iland_count) grid[i][j] = 0 dfs(i-1, j) dfs(i+1, j) dfs(i, j+1) dfs(i, j-1) for i in range(m): for j in range(n): if grid[i][j] == 1: iland_count = 0 dfs(i, j) return ans |
3月16日:字符串压缩
字符串压缩。利用字符重复出现的次数,编写一种方法,实现基本的字符串压缩功能。比如,字符串aabcccccaaa会变为a2b1c5a3。若“压缩”后的字符串没有变短,则返回原先的字符串。你可以假设字符串中只包含大小写英文字母(a至z)。
示例1:
输入:”aabcccccaaa”
输出:”a2b1c5a3″
示例2:
输入:”abbccd”
输出:”abbccd”
解释:”abbccd”压缩后为”a1b2c2d1″,比原字符串长度更长。
思路:
用now
记录重复的字符,count
记录重复的次数。如果当前字符不为now
,则将now
更新为当前字符,count
则重新开始计数。
代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
class Solution: def compressString(self, S: str) -> str: if not S: return '' now = '' ans = '' count = 0 for s in S: if s != now: if count: ans += str(count) now = s count = 1 ans += s else: count += 1 if count: ans += str(count) return ans if len(ans) < len(S) else S |
3月17日:拼写单词
给你一份『词汇表』(字符串数组) words 和一张『字母表』(字符串) chars。
假如你可以用 chars 中的『字母』(字符)拼写出 words 中的某个『单词』(字符串),那么我们就认为你掌握了这个单词。
注意:每次拼写时,chars 中的每个字母都只能用一次。
返回词汇表 words 中你掌握的所有单词的 长度之和。
示例 1:
输入:words = [“cat”,”bt”,”hat”,”tree”], chars = “atach”
输出:6
解释:
可以形成字符串 “cat” 和 “hat”,所以答案是 3 + 3 = 6。
示例 2:
输入:words = [“hello”,”world”,”leetcode”], chars = “welldonehoneyr”
输出:10
解释:
可以形成字符串 “hello” 和 “world”,所以答案是 5 + 5 = 10。
思路:
用一个字典记录每个字母出现的次数,对于words
中的一个单词,每使用一个字母该字母的剩余次数就减1,如果字母够用则能够拼写该单词。
代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
class Solution: def countCharacters(self, words: List[str], chars: str) -> int: char_dict = {} for char in chars: if char not in char_dict: char_dict[char] = 1 else: char_dict[char] += 1 ans = 0 for word in words: can_spell = True char_temp = char_dict.copy() for letter in word: if letter not in char_temp or char_temp[letter] == 0: can_spell = False else: char_temp[letter] -= 1 if can_spell: ans += len(word) return ans |
3月18日:矩形重叠
矩形以列表 [x1, y1, x2, y2] 的形式表示,其中 (x1, y1) 为左下角的坐标,(x2, y2) 是右上角的坐标。
如果相交的面积为正,则称两矩形重叠。需要明确的是,只在角或边接触的两个矩形不构成重叠。
给出两个矩形,判断它们是否重叠并返回结果。
示例 1:
输入:rec1 = [0,0,2,2], rec2 = [1,1,3,3]
输出:true
示例 2:
输入:rec1 = [0,0,1,1], rec2 = [1,0,2,1]
输出:false
思路:
方法一:通过中心点计算,分别在x
和y
方向上比较两个矩形中心的距离
和它们的边长之和
。(这种方法一般也用来判断两个圆是否重合)。
方法二:卡死几种不相交的情况,其他都为True。
代码: 方法一:
1 2 3 4 5 6 7 8 |
class Solution: def isRectangleOverlap(self, rec1: List[int], rec2: List[int]) -> bool: c_1 = [(rec1[0] + rec1[2]) / 2., (rec1[1] + rec1[3]) / 2.] # 计算中点 c_2 = [(rec2[0] + rec2[2]) / 2., (rec2[1] + rec2[3]) / 2.] x = (rec2[2] - rec2[0] + rec1[2] - rec1[0]) / 2. > abs(c_1[0] - c_2[0]) y = (rec2[3] - rec2[1] + rec1[3] - rec1[1]) / 2. > abs(c_1[1] - c_2[1]) return x and y |
方法二:
1 2 3 4 5 6 7 8 9 10 |
class Solution: def isRectangleOverlap(self, rec1: List[int], rec2: List[int]) -> bool: if rec2[1] >= rec1[3] or rec1[1] >= rec2[3]: return False if rec1[0] >= rec2[2] or rec1[2] <= rec2[0]: return False return True |
3月19日:最长回文串
给定一个包含大写字母和小写字母的字符串,找到通过这些字母构造成的最长的回文串。
在构造过程中,请注意区分大小写。比如 “Aa” 不能当做一个回文字符串。
注意:
假设字符串的长度不会超过 1010。
示例 1:
输入:
”abccccdd”
输出:
7
解释:
我们可以构造的最长的回文串是”dccaccd”, 它的长度是 7。
思路:
统计s
中的字母,出现偶数次的全部使用,出现奇数次的少使用一次。最后还可以用一个出现奇数次的字母放在回文串的正中间。
代码:
方法一:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
class Solution: def longestPalindrome(self, s: str) -> int: has_odd = False # 记录是否有奇数次的字母 alpha_dict = {} for char in s: if char not in alpha_dict: alpha_dict[char] = 1 else: alpha_dict[char] += 1 ans = 0 for k in alpha_dict: if alpha_dict[k] % 2 == 0: ans += alpha_dict[k] else: ans += alpha_dict[k] - 1 has_odd = True if has_odd: # 如果有出现奇数次的字母,就拿一个放在回文串的正中间 ans += 1 return ans |
网友给出的一行代码的实现方法:
1 2 3 4 |
class Solution: def longestPalindrome(self, s: str) -> int: len(s) - max(0, sum([s.count(i) % 2 for i in set(s)]) - 1) |
3月20日:最小的k个数
输入整数数组 arr ,找出其中最小的 k 个数。例如,输入4、5、1、6、2、7、3、8这8个数字,则最小的4个数字是1、2、3、4。
示例 1:
输入:arr = [3,2,1], k = 2
输出:[1,2] 或者 [2,1]
示例 2:
输入:arr = [0,1,2,1], k = 1
输出:[0]
思路:
方法一:排序,时间复杂度O(nlogn)
。
方法二:利用快速排序中的partition
,由于每次partition
后左边的数必小于右边的数,因此只需要对k
所在的半边继续partition
即可。时间复杂度<O(nlogn)
。
方法三:构建最小堆,然后取前k个:时间复杂度O(n+klogn)
。
代码:
方法一:
1 2 3 4 5 |
class Solution: def getLeastNumbers(self, arr: List[int], k: int) -> List[int]: arr.sort() return arr[:k] |
方法二:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 |
class Solution: def getLeastNumbers(self, arr: List[int], k: int) -> List[int]: def partition(nums, low, high): pivot = nums[low]; while low < high: while low < high and nums[high] >= pivot: high -= 1 nums[low] = nums[high] while low < high and nums[low] <= pivot: low += 1 nums[high] = nums[low] nums[low]=pivot return low low, high = 0, len(arr)-1 while low < high: i = partition(arr,low,high) if i >= k: high = i - 1 if i <= k: low = i + 1 return arr[:k] |
方法三:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
class Solution: def getLeastNumbers(self, arr: List[int], k: int) -> List[int]: heap = [] for a in arr: heapq.heappush(heap, a) ans = [] for i in range(k): if heap: heap_min = heapq.heappop(heap) # 弹出最小的值 ans.append(heap_min) return ans |
3月21日:水壶问题
有两个容量分别为 x升 和 y升 的水壶以及无限多的水。请判断能否通过使用这两个水壶,从而可以得到恰好 z升 的水?
如果可以,最后请用以上水壶中的一或两个来盛放取得的 z升 水。
你允许:
装满任意一个水壶
清空任意一个水壶
从一个水壶向另外一个水壶倒水,直到装满或者倒空
示例 1: (From the famous “Die Hard” example)
输入: x = 3, y = 5, z = 4
输出: True
示例 2:
输入: x = 2, y = 6, z = 5
输出: False
思路:
找到x
和y
的最大公约数能否z
被整除。另外要保证z <= x + y
。
代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
class Solution: def canMeasureWater(self, x: int, y: int, z: int) -> bool: if z == 0: return True if x == 0: return y == z if y == 0: return x == z def gcd(a, b): if a < b: a, b = b, a while b != 0: a, b = b, a % b return a g = gcd(x, y) return z % g == 0 and z <= x + y |
3月22日:使数组唯一的最小增量
给定整数数组 A,每次 move 操作将会选择任意 A[i],并将其递增 1。
返回使 A 中的每个值都是唯一的最少操作次数。
示例 1:
输入:[1,2,2]
输出:1
解释:经过一次 move 操作,数组将变为 [1, 2, 3]。
示例 2:
输入:[3,2,1,2,1,7]
输出:6
解释:经过 6 次 move 操作,数组将变为 [3, 4, 1, 2, 5, 7]。
可以看出 5 次或 5 次以下的 move 操作是不能让数组的每个值唯一的。
思路:
先将A
排序,然后令cur
=A[0]
,cur
每次+1
,cur
和A[i]
的差即为A[i]
所需要的增量。
当A[i]
大于cur
时,说明A[i]
不需要增量也不会重复了,令cur
=A[i]
。
例如A
=[1,1,2,2,3,7]
时:
cur
=[1,2,3,4,5,7]
, ans
=(2-1)+(3-2)+(4-2)+(5-3)
=6
。
代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
class Solution: def minIncrementForUnique(self, A: List[int]) -> int: A.sort() if len(A) == 0: return 0 cur = A[0] ans = 0 for i in A[1:]: cur += 1 if i > cur: cur = i ans += cur - i return ans |
3月23日:链表的中间结点
给定一个带有头结点 head 的非空单链表,返回链表的中间结点。
如果有两个中间结点,则返回第二个中间结点。
示例 1:
输入:[1,2,3,4,5]
输出:此列表中的结点 3 (序列化形式:[3,4,5])
返回的结点值为 3 。 (测评系统对该结点序列化表述是 [3,4,5])。
注意,我们返回了一个 ListNode 类型的对象 ans,这样:
ans.val = 3, ans.next.val = 4, ans.next.next.val = 5, 以及 ans.next.next.next = NULL.
示例 2:
输入:[1,2,3,4,5,6]
输出:此列表中的结点 4 (序列化形式:[4,5,6])
由于该列表有两个中间结点,值分别为 3 和 4,我们返回第二个结点。
思路:
先遍历一遍算出链表的长度,然后再重新从头取一半返回。
代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
class Solution(object): def middleNode(self, head): """ :type head: ListNode :rtype: ListNode """ temp = head i = 0 while temp: temp = temp.next i += 1 # 长度 for j in range(i//2): # 长度的一半 head = head.next return head |
3月24日:按摩师
一个有名的按摩师会收到源源不断的预约请求,每个预约都可以选择接或不接。在每次预约服务之间要有休息时间,因此她不能接受相邻的预约。给定一个预约请求序列,替按摩师找到最优的预约集合(总预约时间最长),返回总的分钟数。
注意:本题相对原题稍作改动
示例 1:
输入: [1,2,3,1]
输出: 4
解释: 选择 1 号预约和 3 号预约,总时长 = 1 + 3 = 4。
示例 2:
输入: [2,7,9,3,1]
输出: 12
解释: 选择 1 号预约、 3 号预约和 5 号预约,总时长 = 2 + 9 + 1 = 12。
示例 3:
输入: [2,1,4,5,3,1,1,3]
输出: 12
解释: 选择 1 号预约、 3 号预约、 5 号预约和 8 号预约,总时长 = 2 + 4 + 3 + 3 = 12。
思路:
动态规划,dp[i]
表示如果第i
个做了,最大值是多少。因为第i
个做了,要么第i-2
个也做,要么第i-3
个也做。因此有递推公式dp[i]
=nums[i-1]
+max(dp[i-2], dp[i-3])
。
代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
class Solution: def massage(self, nums: List[int]) -> int: n = len(nums) if n == 0: return 0 if n < 3: return max(nums) dp = [0 for i in range(n+1)] dp[0] = 0 # dp[i] 表示第i个做了的最大值 dp[1] = nums[0] dp[2] = nums[1] # nums(0~i] ans = max(dp[1], dp[2]) for i in range(3, n+1): dp[i] = nums[i-1] + max(dp[i-2], dp[i-3]) # 要么做i-2,要么做i-3 ans = max(ans, dp[i]) return ans |
3月25日:三维形体的表面积
在 N * N 的网格上,我们放置一些 1 * 1 * 1 的立方体。
每个值 v = grid[i][j] 表示 v 个正方体叠放在对应单元格 (i, j) 上。
请你返回最终形体的表面积。
示例 1:
输入:[[2]]
输出:10
示例 2:
输入:[[1,2],[3,4]]
输出:34
示例 3:
输入:[[1,0],[0,2]]
输出:16
示例 4:
输入:[[1,1,1],[1,0,1],[1,1,1]]
输出:32
示例 5:
输入:[[2,2,2],[2,1,2],[2,2,2]]
输出:46
思路:
先不考虑左右相邻的情况,高度为h
的正方体有4 * h+2
个面。
考虑两个相邻,矮的会和高的重叠,减少min_height * 2
个面。
代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
class Solution: def surfaceArea(self, grid: List[List[int]]) -> int: m = len(grid) if not m: return 0 n = len(grid[0]) ans = 0 for i in range(m): for j in range(n): if grid[i][j]: ans += grid[i][j] * 4 + 2 if i > 0: ans -= min(grid[i-1][j], grid[i][j]) * 2 # 两个相邻,矮的会和高的重叠,损失min_height * 2个面 if j > 0: ans -= min(grid[i][j-1], grid[i][j]) * 2 return ans |
3月26日:车的可用捕获量
在一个 8 x 8 的棋盘上,有一个白色车(rook)。也可能有空方块,白色的象(bishop)和黑色的卒(pawn)。它们分别以字符 “R”,“.”,“B” 和 “p” 给出。大写字符表示白棋,小写字符表示黑棋。
车按国际象棋中的规则移动:它选择四个基本方向中的一个(北,东,西和南),然后朝那个方向移动,直到它选择停止、到达棋盘的边缘或移动到同一方格来捕获该方格上颜色相反的卒。另外,车不能与其他友方(白色)象进入同一个方格。
返回车能够在一次移动中捕获到的卒的数量。
示例 1:
输入:[[“.”,”.”,”.”,”.”,”.”,”.”,”.”,”.”],[“.”,”.”,”.”,”p”,”.”,”.”,”.”,”.”],[“.”,”.”,”.”,”R”,”.”,”.”,”.”,”p”],[“.”,”.”,”.”,”.”,”.”,”.”,”.”,”.”],[“.”,”.”,”.”,”.”,”.”,”.”,”.”,”.”],[“.”,”.”,”.”,”p”,”.”,”.”,”.”,”.”],[“.”,”.”,”.”,”.”,”.”,”.”,”.”,”.”],[“.”,”.”,”.”,”.”,”.”,”.”,”.”,”.”]]
输出:3
解释:
在本例中,车能够捕获所有的卒。
示例 2:
输入:[[“.”,”.”,”.”,”.”,”.”,”.”,”.”,”.”],[“.”,”p”,”p”,”p”,”p”,”p”,”.”,”.”],[“.”,”p”,”p”,”B”,”p”,”p”,”.”,”.”],[“.”,”p”,”B”,”R”,”B”,”p”,”.”,”.”],[“.”,”p”,”p”,”B”,”p”,”p”,”.”,”.”],[“.”,”p”,”p”,”p”,”p”,”p”,”.”,”.”],[“.”,”.”,”.”,”.”,”.”,”.”,”.”,”.”],[“.”,”.”,”.”,”.”,”.”,”.”,”.”,”.”]]
输出:0
解释:
象阻止了车捕获任何卒。
示例 3:
输入:[[“.”,”.”,”.”,”.”,”.”,”.”,”.”,”.”],[“.”,”.”,”.”,”p”,”.”,”.”,”.”,”.”],[“.”,”.”,”.”,”p”,”.”,”.”,”.”,”.”],[“p”,”p”,”.”,”R”,”.”,”p”,”B”,”.”],[“.”,”.”,”.”,”.”,”.”,”.”,”.”,”.”],[“.”,”.”,”.”,”B”,”.”,”.”,”.”,”.”],[“.”,”.”,”.”,”p”,”.”,”.”,”.”,”.”],[“.”,”.”,”.”,”.”,”.”,”.”,”.”,”.”]]
输出:3
解释:
车可以捕获位置 b5,d6 和 f5 的卒。
思路:
先找到车的位置,再上下左右各自移动判断就好了。
代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 |
class Solution: def numRookCaptures(self, board: List[List[str]]) -> int: ans = 0 for i in range(8): for j in range(8): if board[i][j] == 'R': for k in range(j+1, 8): # 右 if board[i][k] == 'p': ans += 1 if board[i][k] != '.': break for k in range(i+1, 8): # 下 if board[k][j] == 'p': ans += 1 if board[k][j] != '.': break for k in range(j-1,-1,-1): # 左 if board[i][k] == 'p': ans += 1 if board[i][k] != '.': break for k in range(i-1, -1, -1): # 上 if board[k][j] == 'p': ans += 1 if board[k][j] != '.': break return ans |
3月27日:卡牌分组
给定一副牌,每张牌上都写着一个整数。
此时,你需要选定一个数字 X,使我们可以将整副牌按下述规则分成 1 组或更多组:
每组都有 X 张牌。
组内所有的牌上都写着相同的整数。
仅当你可选的 X >= 2 时返回 true。
示例 1:
输入:[1,2,3,4,4,3,2,1]
输出:true
解释:可行的分组是 [1,1],[2,2],[3,3],[4,4]
示例 2:
输入:[1,1,1,2,2,2,3,3]
输出:false
解释:没有满足要求的分组。
示例 3:
输入:1
输出:false
解释:没有满足要求的分组。
示例 4:
输入:[1,1]
输出:true
解释:可行的分组是 [1,1]
示例 5:
输入:[1,1,2,2,2,2]
输出:true
解释:可行的分组是 [1,1],[2,2],[2,2]
思路:
先计数,再求所有出现次数的最大公约数。
代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
class Solution: def hasGroupsSizeX(self, deck: List[int]) -> bool: n = len(deck) if n <= 1: return False dict = {} # 计数 for d in deck: if d in dict: dict[d] += 1 else: dict[d] = 1 l = list(dict.values()) return reduce(math.gcd, l) > 1 |
3月28日:单词的压缩编码
给定一个单词列表,我们将这个列表编码成一个索引字符串 S 与一个索引列表 A。
例如,如果这个列表是 [“time”, “me”, “bell”],我们就可以将其表示为 S = “time#bell#” 和 indexes = [0, 2, 5]。
对于每一个索引,我们可以通过从字符串 S 中索引的位置开始读取字符串,直到 “#” 结束,来恢复我们之前的单词列表。
那么成功对给定单词列表进行编码的最小字符串长度是多少呢?
示例:
输入: words = [“time”, “me”, “bell”]
输出: 10
说明: S = “time#bell#” , indexes = [0, 2, 5] 。
思路:
其实意思就是计算有几个后缀不同
的单词。暴力计算会超时。
将每个字符串都倒序,然后排序,这样就只需要比较相邻的字符串即可。
代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
class Solution: def minimumLengthEncoding(self, words: List[str]) -> int: # 倒序后排序 words = [word[::-1] for word in words] words.sort() n = len(words) ans = 0 for i in range(1, n): # 下一个startswith上一个就不要上一个 if not words[i].startswith(words[i-1]): ans += len(words[i-1]) + 1 ans += len(words[-1]) + 1 # 算上最后一个 return ans |
3月29日:地图分析
你现在手里有一份大小为 N x N 的『地图』(网格) grid,上面的每个『区域』(单元格)都用 0 和 1 标记好了。其中 0 代表海洋,1 代表陆地,你知道距离陆地区域最远的海洋区域是是哪一个吗?请返回该海洋区域到离它最近的陆地区域的距离。
我们这里说的距离是『曼哈顿距离』( Manhattan Distance):(x0, y0) 和 (x1, y1) 这两个区域之间的距离是 |x0 – x1| + |y0 – y1| 。
如果我们的地图上只有陆地或者海洋,请返回 -1。
示例 1:
输入:[[1,0,1],[0,0,0],[1,0,1]]
输出:2
解释:
海洋区域 (1, 1) 和所有陆地区域之间的距离都达到最大,最大距离为 2。
示例 2:
输入:[[1,0,0],[0,0,0],[0,0,0]]
输出:4
解释:
海洋区域 (2, 2) 和所有陆地区域之间的距离都达到最大,最大距离为 4。
思路:
跟腐烂的橘子🍊类似,就直接复制它的代码了。
代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 |
class Solution: def maxDistance(self, grid: List[List[int]]) -> int: m = len(grid) n = len(grid[0]) arounds = [(-1, 0), (1, 0), (0, -1), (0, 1)] sums = sum([sum(line) for line in grid]) if sums == 0 or sums == m * n: return -1 # 没有海洋或没有陆地 lands = [] for i in range(m): for j in range(n): if grid[i][j] == 1: lands.append((i, j)) # 所有陆地 new_rotting = [] def rot(x, y): if x < 0 or y < 0 or x >= m or y >= n: return False if grid[x][y] == 0: grid[x][y] = 1 # 成功腐烂新鲜的橘子,返回True new_rotting.append((x,y)) return True return False ans = 0 while True: new_rotting.clear() has_new_rotting = False # 这一轮是否腐烂了新的橘子 for i, j in lands: for i1, j1 in arounds: if rot(i + i1, j + j1): has_new_rotting = True if not has_new_rotting: return ans lands = new_rotting.copy() ans += 1 |
3月30日:圆圈中最后剩下的数字(约瑟夫环)
0,1,,n-1这n个数字排成一个圆圈,从数字0开始,每次从这个圆圈里删除第m个数字。求出这个圆圈里剩下的最后一个数字。
例如,0、1、2、3、4这5个数字组成一个圆圈,从数字0开始每次删除第3个数字,则删除的前4个数字依次是2、0、4、1,因此最后剩下的数字是3。
示例 1:
输入: n = 5, m = 3
输出: 3
示例 2:
输入: n = 10, m = 17
输出: 2
限制:
1 <= n <= 10^5
1 <= m <= 10^6
思路:
约瑟夫环。
方法一:给每个数字一个标记代表它有没有被删除,每次都逐个遍历,当没有删除的数字累计到m
时,就删除当前数字。由于题目数据量大必定会超时。
方法二:模拟数字的删除,每次删除就把该元素从数组中移除,通过计算下标来获取下一个要删除的位置。(耗时2000ms)
方法三:公式法。f(N,M)=(f(N−1,M)+M)%N
。(耗时80ms)
代码:
方法二:
1 2 3 4 5 6 7 8 9 10 11 12 |
class Solution: def lastRemaining(self, n: int, m: int) -> int: circle = [i for i in range(n)] l = n t = (m-1) % l for i in range(n-1): circle.pop(t) l -= 1 t = (t - 1 + m) % l return circle[0] |
方法三:
1 2 3 4 5 6 7 |
class Solution: def lastRemaining(self, n: int, m: int) -> int: res = 0 for i in range(2, n + 1): res = (res + m ) % i return(res) |
3月31日:排序树组
给你一个整数数组 nums,将该数组升序排列。
示例 1:
输入:nums = [5,2,3,1]
输出:[1,2,3,5]
示例 2:
输入:nums = [5,1,1,2,0,0]
输出:[0,0,1,1,2,5]
提示:
1 <= nums.length <= 50000
-50000 <= nums[i] <= 50000
思路:
nums[i]
是有范围的,使用计数排序比直接sorted
快。
代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
class Solution: def sortArray(self, nums: List[int]) -> List[int]: mem = [0 for i in range(100010)] for num in nums: mem[num+50000] += 1 ans = [] for i, count in enumerate(mem): while count: ans.append(i-50000) count -= 1 return ans |
3月的终于刷完啦~~~撒花✿✿✿