957. N 天后的牢房
思路:
模擬變換,當N天結合后返回 => 當N非常大的時候,超時 => 一般N很大的時候,這種題目必然存在循環,所以記錄找過的狀態,一旦出現已經訪問過的狀態可立即跳出循環。
class Solution:
def prisonAfterNDays(self, cells, N: int):
vis = []
while 1:
if not N:
return cells
if cells in vis:
ind = vis.index(cells)
break
tcell = cells.copy()
for i in range(len(cells)):
if i == 0 or i == len(cells)-1:
tcell[i] = 0
continue
if cells[i-1] == cells[i+1]:
tcell[i] = 1
else:
tcell[i] = 0
vis.append(cells)
cells = tcell
N -= 1
vis = vis[ind:]
return vis[N % len(vis)]
825. 適齡的朋友
思路:
最直觀的就是兩層循環暴力,意料之中的超時了。那么就改以人為單位交友,變為以組(年齡相同的為一組)為單位交友。
還需要注意的一點就是15歲以下的沒朋友,不符合第一個條件!
from collections import Counter
class Solution:
def numFriendRequests(self, ages) -> int:
ages, res = sorted(Counter(ages).items(), key=lambda x: x[0]), 0
for i in range(len(ages)):
if ages[i][0] < 15:
continue
res += (ages[i][1] - 1) * ages[i][1]
for j in range(i):
if ages[j][0] <= (ages[i][0] * 0.5 + 7):
continue
else:
res += ages[i][1] * ages[j][1]
return res
781. 森林中的兔子
思路:
顏色相同的兔子如果說自己有i個伙伴,那么所有伙伴都出現,該顏色對應的數字最多出現 i+1次 => 通過頻率來判斷,那些是同樣顏色的。
"""
判斷某數字出現的頻次,數字0特殊處理一下
數字i出現的頻次小於等於i+1時,說明大家都是一個色。
大於i+1的時候,就說明還有別的顏色,看是i+1的幾倍就 i+1 * ?
"""
import math
from collections import Counter
class Solution:
def numRabbits(self, answers) -> int:
ans, res = Counter(answers), 0
for num, times in ans.items():
if not num:
res += times
else:
if times <= num + 1:
res += num + 1
else:
t = math.ceil(times / (num + 1))
res += t * (num + 1)
return res
1324. 豎直打印單詞
思路:
補上空格,矩陣轉置輸出,末尾的空格需要去掉。
class Solution:
def printVertically(self, s: str):
s = s.split(" ")
l = len(sorted(s, key=lambda x:-len(x))[0])
for i in range(len(s)):
s[i] = s[i] + (l - len(s[i])) * " "
res = []
for i in zip(*s):
i = ("".join(list(i))).rstrip()
res.append(i)
return res
816. 模糊坐標
思路:
分割數組找到整數、小數部分。比較麻煩在於加上小數點后時候合理:
- 不是‘0’也不是'0.'但以0開頭的不合理
- 以‘0’結尾的不合理
"""
先分割字符串,得到整數部分和小數部分,再分別為兩部分加上小數點,同時判斷加上小數點后是否為合理數字
"""
class Solution:
def ambiguousCoordinates(self, S: str):
def produce(string):
res = []
# 本身就是一個完整的數字
if len(str(int(string))) == len(string):
res = [string]
# 如果全是零直接返回
if set(string) == {'0'}:
return res
# 在不同的位置添加小數點
for i in range(1,len(string)):
t = string[:i]+"."+string[i:]
# 不是'0'也不是'0.'開頭的,以'0'開頭的都要刪掉
if len(string[:i]) >= 2 and string[:i].startswith("0"):
continue
# '0'結尾的也刪掉
if string[i:].endswith('0'):
continue
res.append(t)
return res
S, res, r = S[1:-1], [], []
# 分割字符串獲取整數、小數部分
for i in range(1, len(S)):
res.append((S[:i], S[i:]))
for x, y in res:
px = produce(x)
py = produce(y)
for i in px:
for j in py:
r.append("("+i+", "+j+")")
return r
56. 合並區間
思路:
按照合並的要求來就vans了。先排序,保證遍歷的時候后面的要么是頭比前面大,要么是尾巴更長。記錄當前拼接的頭尾,如果遇到了頭比當前拼接的尾巴還大,這兩個區間不可能合並的,重新開始一次拼接,否則更新尾巴。
class Solution:
def merge(self, intervals):
res = []
# 先排序
intervals = sorted(intervals)
# 記錄拼接的首尾大小
s, e = intervals[0][0], intervals[0][1]
for x, y in intervals[1:]:
# 你的頭大於我的尾部,不可能拼接的。重新開始一次拼接
if x > e:
res.append([s, e])
s, e = x, y
continue
# 可以拼接到一起,更新尾巴
if y > e:
e = y
if [s, e] not in res:
res.append([s, e])
return res