leetcode刷題系列
來源:力扣(LeetCode)
鏈接:https://leetcode-cn.com/problems/trapping-rain-water
著作權歸領扣網絡所有。商業轉載請聯系官方授權,非商業轉載請注明出處。
輸入整數數組 arr ,找出其中最小的 k 個數。例如,輸入4、5、1、6、2、7、3、8這8個數字,則最小的4個數字是1、2、3、4。
版本1:超出時間限制:
class Solution(object):
def getLeastNumbers(self, arr, k):
"""
:type arr: List[int]
:type k: int
:rtype: List[int]
"""
Bucket = [0]*(max(arr)- min(arr) +1) #創建并初始化桶
for i in range(len(arr)):
#把所有的元素放入桶中,即把對應的元素+1
Bucket[arr[i]-min(arr)] += 1
temp = []
for i in range(len(Bucket)):
#取出桶中的元素
if Bucket[i] != 0:
temp += [min(arr) + i] * Bucket[i]
return temp[0:k]
運行時間有點長,其他的沒毛病
class Solution(object):
def getLeastNumbers(self, arr, k):
"""
:type arr: List[int]
:type k: int
:rtype: List[int]
"""
if k > len(arr) or k <= 0:
return []
start = 0
end = len(arr) - 1
arr = self.quickSort(arr, start, end)
return arr[:k]
def partition(self,arr,low,high):
i = ( low-1 ) # 最小元素索引
pivot = arr[high]
for j in range(low , high):
# 當前元素小于或等于 pivot
if arr[j] <= pivot:
i = i+1
arr[i],arr[j] = arr[j],arr[i]
arr[i+1],arr[high] = arr[high],arr[i+1]
return ( i+1 )
def quickSort(self,arr,low,high):
if low < high:
pi = self.partition(arr,low,high)
self.quickSort(arr, low, pi-1)
self.quickSort(arr, pi+1, high)
return arr
正確答案
class Solution(object):
def getLeastNumbers(self, arr, k):
"""
:type arr: List[int]
:type k: int
:rtype: List[int]
"""
# 方法一:partition方法(基于快速排序)
if k > len(arr) or k <= 0:
return []
start = 0
end = len(arr) - 1
index = self.quickSort(arr, start, end)
while index != k-1:
print(index)
if index > k-1:
end = index - 1
index = self.quickSort(arr, start, end)
if index < k-1:
start = index + 1
index = self.quickSort(arr, start, end)
return arr[:k]
def quickSort(self, arr, start, end):
low = start
high = end
temp = arr[start]
while low < high:
while low < high and arr[high] >= temp:
high -= 1
arr[low] = arr[high]
while low <high and arr[low] < temp:
low += 1
arr[high] = arr[low]
arr[low] = temp
return low
給定一個整數數組 nums 和一個目標值 target,請你在該數組中找出和為目標值的那 兩個 整數,并返回他們的數組下標。
你可以假設每種輸入只會對應一個答案。但是,你不能重復利用這個數組中同樣的元素
class Solution(object):
def twoSum(self, nums, target):
"""
:type nums: List[int]
:type target: int
:rtype: List[int]
"""
d={}
n=0
for i in nums:
if d.has_key(i):
tmp=d[i]
tmp.append(n)
d[i]=tmp
else :
tmp=[]
tmp.append(n)
d[i]=tmp
n+=1
for i in nums:
tmp=0
tmp=target-i
if tmp!=i and tmp in nums:
return nums.index(tmp),nums.index(i)
elif tmp==i and len(d[i])>=2:
return d[i][0],d[i][1]
else :
print 'none'
正確解法
def twoSum(nums, target):
hashmap={}
for i,num in enumerate(nums):
if hashmap.get(target - num) is not None:
return [i,hashmap.get(target - num)]
hashmap[num] = i #這句不能放在if語句之前,解決list中有重復值或target-num=num的情況
水壺問題:有兩個容量分別為 x升 和 y升 的水壺以及無限多的水。請判斷能否通過使用這兩個水壺,從而可以得到恰好 z升 的水?
順便復習了數學中的貝祖定理
class Solution:
def canMeasureWater(self, x: int, y: int, z: int) -> bool:
if x + y < z:
return False
if x == 0 or y == 0:
return z == 0 or x + y == z
return z % math.gcd(x, y) == 0
給定整數數組 A,每次 move 操作將會選擇任意 A[i],并將其遞增 1。
返回使 A 中的每個值都是唯一的最少操作次數。
class Solution(object):
def minIncrementForUnique(self, A):
"""
:type A: List[int]
:rtype: int
"""
count = [0] * 80000
for x in A:
count[x] += 1
ans = taken = 0
for x in range(80000):
if count[x] >= 2:
taken += count[x] - 1
ans -= x * (count[x] - 1)
elif taken > 0 and count[x] == 0:
taken -= 1
ans += x
return ans
給定一個帶有頭結點 head 的非空單鏈表,返回鏈表的中間結點。
如果有兩個中間結點,則返回第二個中間結點。
class Solution(object):
def middleNode(self, head):
"""
:type head: ListNode
:rtype: ListNode
"""
tmp=head
n=0
while tmp!=None:
n+=1
tmp=tmp.next
cnt=n//2 +1
tmp=head
n=0
while tmp!=None:
n+=1
if n==cnt:
return tmp
tmp=tmp.next
一個有名的按摩師會收到源源不斷的預約請求,每個預約都可以選擇接或不接。在每次預約服務之間要有休息時間,因此她不能接受相鄰的預約。給定一個預約請求序列,替按摩師找到最優的預約集合(總預約時間最長),返回總的分鐘數。
自己解答:有問題,沒考慮到【2,1,1,2】的情況。
class Solution(object):
def massage(self, nums):
"""
:type nums: List[int]
:rtype: int
"""
return max(sum(nums[::2]),sum(nums[1::2]))
正確解答:動態規劃(用n-1的狀態更新n的狀態)
class Solution(object):
def massage(self, nums):
"""
:type nums: List[int]
:rtype: int
"""
n = len(nums)
if n == 0:
return 0
dp0, dp1 = 0, nums[0]
for i in range(1, n):
tdp0 = max(dp0, dp1) # 計算 dp[i][0]
tdp1 = dp0 + nums[i] # 計算 dp[i][1]
dp0, dp1 = tdp0, tdp1
return max(dp0, dp1)
在 N * N 的網格上,我們放置一些 1 * 1 * 1 的立方體。
每個值 v = grid[i][j] 表示 v 個正方體疊放在對應單元格 (i, j) 上。
請你返回最終形體的表面積。
class Solution(object):
def surfaceArea(self, grid):
N = len(grid)
ans = 0
for r in xrange(N):
for c in xrange(N):
if grid[r][c]:
ans += 2
for nr, nc in ((r-1, c), (r+1, c), (r, c-1), (r,c+1)):
if 0 <= nr < N and 0 <= nc < N:
nval = grid[nr][nc]
else:
nval = 0
ans += max(grid[r][c] - nval, 0)
return ans
在一個 8 x 8 的棋盤上,有一個白色車(rook)。也可能有空方塊,白色的象(bishop)和黑色的卒(pawn)。它們分別以字符 “R”,“.”,“B” 和 “p” 給出。大寫字符表示白棋,小寫字符表示黑棋。
車按國際象棋中的規則移動:它選擇四個基本方向中的一個(北,東,西和南),然后朝那個方向移動,直到它選擇停止、到達棋盤的邊緣或移動到同一方格來捕獲該方格上顏色相反的卒。另外,車不能與其他友方(白色)象進入同一個方格。
返回車能夠在一次移動中捕獲到的卒的數量。
超出了時間限制:
dx,dy=[0,1,0,-1],[1,0,-1,0]
cnt=line_x=line_y=0
for i in range(8):
if 'R' in board[i]:
line_x=i
line_y=board[i].index('R')
for i in range(4):
step=0
while True:
x=line_x+step*dx[i]
y=line_y+step*dx[i]
if x<0 or x>=8 or y<0 or y>=8 or board[x][y]=='p':
break
if board[x][y]=='.':
cnt+=1
break
step+=1
return cnt
再來一次:
class Solution(object):
def numRookCaptures(self, board):
"""
:type board: List[List[str]]
:rtype: int
"""
result=0
for i in range(len(board)):
if 'R' in board[i]:
raw = i
break
colum = board[raw].index('R')
s = ''.join(board[raw])
s = s.replace('.','')
if 'pR' in s:
result += 1
if 'Rp' in s:
result += 1
s = ''.join(i[colum] for i in board)
s = s.replace('.','')
if 'pR' in s:
result += 1
if 'Rp' in s:
result += 1
return result
給定一副牌,每張牌上都寫著一個整數。
此時,你需要選定一個數字 X,使我們可以將整副牌按下述規則分成 1 組或更多組:
每組都有 X 張牌。
組內所有的牌上都寫著相同的整數。
僅當你可選的 X >= 2 時返回 true。
class Solution(object):
def hasGroupsSizeX(self, deck):
"""
:type deck: List[int]
:rtype: bool
"""
from fractions import gcd
vals = collections.Counter(deck).values()
return reduce(gcd, vals) >= 2
給定一個單詞列表,我們將這個列表編碼成一個索引字符串 S 與一個索引列表 A。
例如,如果這個列表是 ["time", "me", "bell"],我們就可以將其表示為 S = "time#bell#" 和 indexes = [0, 2, 5]。
對于每一個索引,我們可以通過從字符串 S 中索引的位置開始讀取字符串,直到 "#" 結束,來恢復我們之前的單詞列表。
那么成功對給定單詞列表進行編碼的最小字符串長度是多少呢?
class Solution(object):
def minimumLengthEncoding(self, words):
"""
:type words: List[str]
:rtype: int
"""
word_set=set(words)
for word in words:
for k in range(1,len(word)):
word_set.discard(word[k:])
return sum(len(word)+1 for word in word_set
你現在手里有一份大小為 N x N 的『地圖』(網格) grid,上面的每個『區域』(單元格)都用 0 和 1 標記好了。其中 0 代表海洋,1 代表陸地,你知道距離陸地區域最遠的海洋區域是是哪一個嗎?請返回該海洋區域到離它最近的陸地區域的距離。
我們這里說的距離是『曼哈頓距離』( Manhattan Distance):(x0, y0) 和 (x1, y1) 這兩個區域之間的距離是 |x0 - x1| + |y0 - y1| 。
如果我們的地圖上只有陸地或者海洋,請返回 -1。
class Solution(object):
def maxDistance(self, grid):
"""
:type grid: List[List[int]]
:rtype: int
"""
N = len(grid)
queue = []
# 將所有的陸地格子加入隊列
for i in range(N):
for j in range(N):
if grid[i][j] == 1:
queue.append((i, j))
# 如果我們的地圖上只有陸地或者海洋,請返回 -1。
if len(queue) == 0 or len(queue) == N * N:
return -1
distance = -1
while len(queue) > 0:
distance += 1
# 這里一口氣取出 n 個結點,以實現層序遍歷
n = len(queue)
for i in range(n):
r, c = queue.pop(0)
# 遍歷上邊單元格
if r-1 >= 0 and grid[r-1][c] == 0:
grid[r-1][c] = 2
queue.append((r-1, c))
# 遍歷下邊單元格
if r+1 < N and grid[r+1][c] == 0:
grid[r+1][c] = 2
queue.append((r+1, c))
# 遍歷左邊單元格
if c-1 >= 0 and grid[r][c-1] == 0:
grid[r][c-1] = 2
queue.append((r, c-1))
# 遍歷右邊單元格
if c+1 < N and grid[r][c+1] == 0:
grid[r][c+1] = 2
queue.append((r, c+1))
return distance
0,1,,n-1這n個數字排成一個圓圈,從數字0開始,每次從這個圓圈里刪除第m個數字。求出這個圓圈里剩下的最后一個數字。
例如,0、1、2、3、4這5個數字組成一個圓圈,從數字0開始每次刪除第3個數字,則刪除的前4個數字依次是2、0、4、1,因此最后剩下的數字是3。
(還是用動態規劃解決的)
def f(n, m):
if n == 0:
return 0
x = f(n - 1, m)
return (m + x) % n
class Solution(object):
def lastRemaining(self, n, m):
"""
:type n: int
:type m: int
:rtype: int
"""
return f(n, m)
全局排序
class Solution(object):
def sortArray(self, nums):
"""
:type nums: List[int]
:rtype: List[int]
"""
return self.qsort(nums)
def qsort(self,nums):
if len(nums) <= 1:
return nums
else:
pivot = nums[0]
less = [x for x in nums[1:] if x < pivot]
greater = [x for x in nums[1:] if x >= pivot]
return self.qsort(less) + [pivot] + self.qsort(greater)
有效括號字符串 定義:對于每個左括號,都能找到與之對應的右括號,反之亦然。詳情參見題末「有效括號字符串」部分。
嵌套深度 depth 定義:即有效括號字符串嵌套的層數,depth(A) 表示有效括號字符串 A 的嵌套深度。詳情參見題末「嵌套深度」部分。
class Solution(object):
def maxDepthAfterSplit(self, seq):
"""
:type seq: str
:rtype: List[int]
"""
ans=[]
d=0
for c in seq:
if c=='(':
d+=1
ans.append(d % 2)
if c==')':
ans.append(d% 2)
d-=1
return ans
根據 百度百科 ,生命游戲,簡稱為生命,是英國數學家約翰·何頓·康威在 1970 年發明的細胞自動機。
給定一個包含 m × n 個格子的面板,每一個格子都可以看成是一個細胞。每個細胞都具有一個初始狀態:1 即為活細胞(live),或 0 即為死細胞(dead)。每個細胞與其八個相鄰位置(水平,垂直,對角線)的細胞都遵循以下四條生存定律:
如果活細胞周圍八個位置的活細胞數少于兩個,則該位置活細胞死亡;
如果活細胞周圍八個位置有兩個或三個活細胞,則該位置活細胞仍然存活;
如果活細胞周圍八個位置有超過三個活細胞,則該位置活細胞死亡;
如果死細胞周圍正好有三個活細胞,則該位置死細胞復活;
根據當前狀態,寫一個函數來計算面板上所有細胞的下一個(一次更新后的)狀態。下一個狀態是通過將上述規則同時應用于當前狀態下的每個細胞所形成的,其中細胞的出生和死亡是同時發生的。
class Solution(object):
def gameOfLife(self, board):
"""
:type board: List[List[int]]
:rtype: None Do not return anything, modify board in-place instead.
"""
neighbor=[(1,0),(0,1),(-1,0),(0,-1),(1,1),(1,-1),(-1,-1),(-1,1)]
for i in range(len(board)):
for j in range(len(board[i])):
living_neibhbor=0
for (r,c) in neighbor:
row=r+i
col=c+j
if (row>=0 and row<len(board)) and (col>=0 and col<len(board[0])) and abs(board[row][col])==1:
living_neibhbor+=1
if (board[i][j]==1) and (living_neibhbor<2 or living_neibhbor>3):
board[i][j]=-1
if (board[i][j]==0) and (living_neibhbor==3):
board[i][j]=2
print board
for i in range(len(board)):
for j in range(len(board[i])):
if board[i][j] > 0:
board[i][j] = 1
else:
board[i][j] = 0
return board
請你來實現一個 atoi 函數,使其能將字符串轉換成整數。
首先,該函數會根據需要丟棄無用的開頭空格字符,直到尋找到第一個非空格的字符為止。接下來的轉化規則如下:
如果第一個非空字符為正或者負號時,則將該符號與之后面盡可能多的連續數字字符組合起來,形成一個有符號整數。
假如第一個非空字符是數字,則直接將其與之后連續的數字字符組合起來,形成一個整數。
該字符串在有效的整數部分之后也可能會存在多余的字符,那么這些字符可以被忽略,它們對函數不應該造成影響。
注意:假如該字符串中的第一個非空格字符不是一個有效整數字符、字符串為空或字符串僅包含空白字符時,則你的函數不需要進行轉換,即無法進行有效轉換。
在任何情況下,若函數不能進行有效的轉換時,請返回 0 。
提示:
本題中的空白字符只包括空格字符 ' ' 。
假設我們的環境只能存儲 32 位大小的有符號整數,那么其數值范圍為 [?231, 231 ? 1]。如果數值超過這個范圍,請返回 INT_MAX (231 ? 1) 或 INT_MIN (?231) 。
class Solution(object):
def myAtoi(self, str):
"""
:type str: str
:rtype: int
"""
return max(min(int(*re.findall('^[\+\-]?\d+', str.lstrip())), 2**31 - 1), -2**31)
給定 n 個非負整數表示每個寬度為 1 的柱子的高度圖,計算按此排列的柱子,下雨之后能接多少雨水。
上面是由數組 [0,1,0,2,1,0,1,3,2,1,2,1] 表示的高度圖,在這種情況下,可以接 6 個單位的雨水(藍色部分表示雨水)。 感謝 Marcos 貢獻此圖。
超出時間限制,難受
class Solution(object):
def trap(self, height):
"""
:type height: List[int]
:rtype: int
"""
if len(height)==0:
return 0
re=[]
for h in height:
re_tmp=[0] * max(height)
for j in range(h):
re_tmp[j]=1
re.append(re_tmp)
rain=0
for j in range(max(height)):
left=0
for i in range(len(height)):
if left==0 and re[i][j]==1:
left+=1
rain_tmp=0
elif left==1 and re[i][j]==0:
rain_tmp+=1
print i,j
print re[i][j],left,rain
elif left==1 and re[i][j]==1 and rain_tmp!=0 :
rain+=rain_tmp
rain_tmp=0
return rain
正確答案:
class Solution(object):
def trap(self, height):
"""
:type height: List[int]
:rtype: int
"""
n = len(height)
# 同時從左往右和從右往左計算有效面積
s1, s2 = 0, 0
max1, max2 = 0, 0
for i in range(n):
if height[i] > max1:
max1 = height[i]
if height[n - i - 1] > max2:
max2 = height[n - i - 1]
s1 += max1
s2 += max2
# 積水面積 = S1 + S2 - 矩形面積 - 柱子面積
res = s1 + s2 - max1 * len(height) - sum(height)
return res
徹底跪,只能抄答案:
設計并實現最不經常使用(LFU)緩存的數據結構。它應該支持以下操作:get 和 put。
get(key) - 如果鍵存在于緩存中,則獲取鍵的值(總是正數),否則返回 -1。
put(key, value) - 如果鍵不存在,請設置或插入值。當緩存達到其容量時,它應該在插入新項目之前,使最不經常使用的項目無效。在此問題中,當存在平局(即兩個或更多個鍵具有相同使用頻率)時,最近最少使用的鍵將被去除。
進階:
你是否可以在 O(1) 時間復雜度內執行兩項操作?
class dlNode:
def __init__(self, key, val, cnt=0):
self.val = [key, val, cnt]#鍵、值、訪問次數
self.pre = None
self.nxt = None
class LFUCache:
def __init__(self, capacity: int):
self.cache = {}#通過key保存鏈表節點,key:node
self.c = capacity#字典容量
self.head = dlNode(1, 1, float('inf'))#頭節點,定義訪問次數正無窮
self.tail = dlNode(-1, -1, float('-inf'))#尾節點,定義訪問次數負無窮
self.head.nxt = self.tail
self.tail.pre = self.head
def _refresh(self, node, cnt):##輔助函數,對節點node,以訪問次數cnt重新定義其位置
pNode, nNode = node.pre, node.nxt #當前節點的前后節點
if cnt < pNode.val[2]:#如果訪問次數小于前節點的訪問次數,無需更新位置
return
pNode.nxt, nNode.pre = nNode, pNode#將前后連起來,跳過node位置
while cnt >= pNode.val[2]:#前移到盡可能靠前的位置后插入
pNode = pNode.pre
nNode = pNode.nxt
pNode.nxt = nNode.pre = node
node.pre, node.nxt = pNode, nNode
def get(self, key: int) -> int:
if self.c <= 0 or key not in self.cache:#如果容量<=0或者key不在字典中,直接返回-1
return -1
node = self.cache[key]#通過字典找到節點
_, value, cnt = node.val#通過節點得到key,value和cnt
node.val[2] = cnt+1#訪問次數+1
self._refresh(node, cnt+1)#刷新位置
return value
def put(self, key: int, value: int) -> None:
if self.c <= 0:#緩存容量<=0
return
if key in self.cache:#已在字典中,則要更新其value,同時訪問次數+1刷新位置
node = self.cache[key]
_, _, cnt = node.val
node.val = [key, value, cnt+1]#更新其值
self._refresh(node, cnt+1)
else:
if len(self.cache) >= self.c: #容量已滿,先清除掉尾部元素
tp, tpp = self.tail.pre, self.tail.pre.pre
self.cache.pop(tp.val[0]) #從字典剔除尾節點
tpp.nxt, self.tail.pre = self.tail, tpp #首尾相連,跳過原尾節點
#新建節點,并先插入到隊尾
node = dlNode(key, value)
node.pre, node.nxt = self.tail.pre, self.tail
self.tail.pre.nxt, self.tail.pre = node, node
self.cache[key] = node
self._refresh(node, 0)
# Your LFUCache object will be instantiated and called as such:
# obj = LFUCache(capacity)
# param_1 = obj.get(key)
# obj.put(key,value)
給你兩個單詞 word1 和 word2,請你計算出將 word1 轉換成 word2 所使用的最少操作數 。
你可以對一個單詞進行如下三種操作:
插入一個字符
刪除一個字符
替換一個字符
class Solution(object):
def minDistance(self, word1, word2):
"""
:type word1: str
:type word2: str
:rtype: int
"""
n=len(word1)
m=len(word2)
if n*m==0:
return n+m
dp=[[0] * (m+1) for _ in range(n+1)]
for j in range(m+1):
dp[0][j]=j
for i in range(n+1):
dp[i][0]=i
for i in range(1, n + 1):
for j in range(1,m+1):
left=dp[i-1][j]+1
down=dp[i][j-1]+1
left_down=dp[i-1][j-1]
if word1[i-1]!=word2[j-1]:
left_down+=1
dp[i][j]=min(left,down,left_down)
return dp[n][m]
矩陣轉置:
基于這個公式:
?
class Solution:
def rotate(self, matrix: List[List[int]]) -> None:
n = len(matrix)
for i in range(n // 2):
for j in range((n + 1) // 2):
matrix[i][j], matrix[n - j - 1][i], matrix[n - i - 1][n - j - 1], matrix[j][n - i - 1] \
= matrix[n - j - 1][i], matrix[n - i - 1][n - j - 1], matrix[j][n - i - 1], matrix[i][j]
地上有一個m行n列的方格,從坐標 [0,0] 到坐標 [m-1,n-1] 。
一個機器人從坐標 [0, 0] 的格子開始移動,它每次可以向左、右、上、下移動一格(不能移動到方格外),
也不能進入行坐標和列坐標的數位之和大于k的格子。例如,當k為18時,機器人能夠進入方格 [35, 37] ,
因為3+5+3+7=18。但它不能進入方格 [35, 38],因為3+5+3+8=19。請問該機器人能夠到達多少個格子?
def digitsum(n):
ans=0
while n:
ans+=n%10
n //= 10
return ans
class Solution(object):
def movingCount(self, m, n, k):
"""
:type m: int
:type n: int
:type k: int
:rtype: int
"""
vis=set([(0,0)])
for i in range(m):
for j in range(n):
if ((i - 1, j) in vis or (i, j - 1) in vis) and digitsum(i) + digitsum(j) <= k:
vis.add((i, j))
return len(vis)
數字 n 代表生成括號的對數,請你設計一個函數,用于能夠生成所有可能的并且 有效的 括號組合。
class Solution:
def generateParenthesis(self, n):
ans = []
def backtrack(S, left, right):
if len(S) == 2 * n:
ans.append(''.join(S))
return
if left < n:
S.append('(')
backtrack(S, left+1, right)
S.pop()
if right < left:
S.append(')')
backtrack(S, left, right+1)
S.pop()
backtrack([], 0, 0)
return ans
你將獲得 K 個雞蛋,并可以使用一棟從 1 到 N 共有 N 層樓的建筑。
每個蛋的功能都是一樣的,如果一個蛋碎了,你就不能再把它掉下去。
你知道存在樓層 F ,滿足 0 <= F <= N 任何從高于 F 的樓層落下的雞蛋都會碎,從 F 樓層或比它低的樓層落下的雞蛋都不會破。
每次移動,你可以取一個雞蛋(如果你有完整的雞蛋)并把它從任一樓層 X 扔下(滿足 1 <= X <= N)。
你的目標是確切地知道 F 的值是多少。
無論 F 的初始值如何,你確定 F 的值的最小移動次數是多少?
給定一個字符串,逐個翻轉字符串中的每個單詞。
class Solution(object):
def reverseWords(self, s):
"""
:type s: str
:rtype: str
"""
return " ".join(reversed(s.split()))
class Solution(object):
def superEggDrop(self, K, N):
"""
:type K: int
:type N: int
:rtype: int
"""
if N==1:
return 1
dp=[[0] * (K+1) for _ in range(N+1) ]
for i in range(1,K+1):
dp[1][i]=1
ans=0
for i in range(2,N+1):
for j in range(1,K+1):
dp[i][j]=1+dp[i-1][j]+dp[i-1][j-1]
if dp[i][j]>=N:
ans=i
break
return ans
給定兩條線段(表示為起點start = {X1, Y1}和終點end = {X2, Y2}),如果它們有交點,請計算其交點,沒有交點則返回空值。
要求浮點型誤差不超過10^-6。若有多個交點(線段重疊)則返回 X 值最小的點,X 坐標相同則返回 Y 值最小的點。
class Solution:
def intersection(self, start1: List[int], end1: List[int], start2: List[int], end2: List[int]) -> List[float]:
# 判斷 (xk, yk) 是否在「線段」(x1, y1)~(x2, y2) 上
# 這里的前提是 (xk, yk) 一定在「直線」(x1, y1)~(x2, y2) 上
def inside(x1, y1, x2, y2, xk, yk):
# 若與 x 軸平行,只需要判斷 x 的部分
# 若與 y 軸平行,只需要判斷 y 的部分
# 若為普通線段,則都要判斷
return (x1 == x2 or min(x1, x2) <= xk <= max(x1, x2)) and (y1 == y2 or min(y1, y2) <= yk <= max(y1, y2))
def update(ans, xk, yk):
# 將一個交點與當前 ans 中的結果進行比較
# 若更優則替換
return [xk, yk] if not ans or [xk, yk] < ans else ans
x1, y1 = start1
x2, y2 = end1
x3, y3 = start2
x4, y4 = end2
ans = list()
# 判斷 (x1, y1)~(x2, y2) 和 (x3, y3)~(x4, y3) 是否平行
if (y4 - y3) * (x2 - x1) == (y2 - y1) * (x4 - x3):
# 若平行,則判斷 (x3, y3) 是否在「直線」(x1, y1)~(x2, y2) 上
if (y2 - y1) * (x3 - x1) == (y3 - y1) * (x2 - x1):
# 判斷 (x3, y3) 是否在「線段」(x1, y1)~(x2, y2) 上
if inside(x1, y1, x2, y2, x3, y3):
ans = update(ans, x3, y3)
# 判斷 (x4, y4) 是否在「線段」(x1, y1)~(x2, y2) 上
if inside(x1, y1, x2, y2, x4, y4):
ans = update(ans, x4, y4)
# 判斷 (x1, y1) 是否在「線段」(x3, y3)~(x4, y4) 上
if inside(x3, y3, x4, y4, x1, y1):
ans = update(ans, x1, y1)
# 判斷 (x2, y2) 是否在「線段」(x3, y3)~(x4, y4) 上
if inside(x3, y3, x4, y4, x2, y2):
ans = update(ans, x2, y2)
# 在平行時,其余的所有情況都不會有交點
else:
# 聯立方程得到 t1 和 t2 的值
x1,x2,x3,x4=float(x1),float(x2),float(x3),float(x4)
y1,y2,y3,y4=float(y1),float(y2),float(y3),float(y4)
t1 = (x3 * (y4 - y3) + y1 * (x4 - x3) - y3 * (x4 - x3) - x1 * (y4 - y3)) / ((x2 - x1) * (y4 - y3) - (x4 - x3) * (y2 - y1))
t2 = (x1 * (y2 - y1) + y3 * (x2 - x1) - y1 * (x2 - x1) - x3 * (y2 - y1)) / ((x4 - x3) * (y2 - y1) - (x2 - x1) * (y4 - y3))
# 判斷 t1 和 t2 是否均在 [0, 1] 之間
if 0.0 <= t1 <= 1.0 and 0.0 <= t2 <= 1.0:
ans = [x1 + t1 * (x2 - x1), y1 + t1 * (y2 - y1)]
return ans
設計一個簡化版的推特(Twitter),可以讓用戶實現發送推文,關注/取消關注其他用戶,能夠看見關注人(包括自己)的最近十條推文。你的設計需要支持以下的幾個功能:
postTweet(userId, tweetId): 創建一條新的推文
getNewsFeed(userId): 檢索最近的十條推文。每個推文都必須是由此用戶關注的人或者是用戶自己發出的。推文必須按照時間順序由最近的開始排序。
follow(followerId, followeeId): 關注一個用戶
unfollow(followerId, followeeId): 取消關注一個用戶
來源:力扣(LeetCode)
鏈接:https://leetcode-cn.com/problems/design-twitter
著作權歸領扣網絡所有。商業轉載請聯系官方授權,非商業轉載請注明出處。
class Twitter(object):
def __init__(self):
"""
Initialize your data structure here.
"""
self.users=dict()
self.posts=[]
def postTweet(self, userId, tweetId):
"""
Compose a new tweet.
:type userId: int
:type tweetId: int
:rtype: None
"""
self.posts.append([userId,tweetId])
if userId not in self.users.keys():
self.users[userId]=[]
def getNewsFeed(self, userId):
"""
Retrieve the 10 most recent tweet ids in the user's news feed. Each item in the news feed must be posted by users who the user followed or by the user herself. Tweets must be ordered from most recent to least recent.
:type userId: int
:rtype: List[int]
"""
if userId not in self.users.keys():
return
else :
idx=[userId]+self.users.get(userId)
tmp=[]
count=10
for post in self.posts[-1:-len(self.posts)-1:-1]:
if count>0:
if post[0] in idx:
tmp.append(post[1])
count-=1
return tmp
def follow(self, followerId, followeeId):
"""
Follower follows a followee. If the operation is invalid, it should be a no-op.
:type followerId: int
:type followeeId: int
:rtype: None
"""
if followerId not in self.users.keys():
self.users[followerId]=[]
self.users[followerId].append(followeeId)
else:
self.users[followerId].append(followeeId)
def unfollow(self, followerId, followeeId):
"""
Follower unfollows a followee. If the operation is invalid, it should be a no-op.
:type followerId: int
:type followeeId: int
:rtype: None
"""
if followerId not in self.users.keys():
return
elif followeeId not in self.users[followerId]:
return
else :
self.users[followerId].remove(followeeId)
# Your Twitter object will be instantiated and called as such:
# obj = Twitter()
# obj.postTweet(userId,tweetId)
# param_2 = obj.getNewsFeed(userId)
# obj.follow(followerId,followeeId)
# obj.unfollow(followerId,followeeId)
給你兩個 非空 鏈表來代表兩個非負整數。數字最高位位于鏈表開始位置。它們的每個節點只存儲一位數字。將這兩數相加會返回一個新的鏈表。
你可以假設除了數字 0 之外,這兩個數字都不會以零開頭。
# Definition for singly-linked list.
# class ListNode(object):
# def __init__(self, x):
# self.val = x
# self.next = None
class Solution(object):
def addTwoNumbers(self, l1, l2):
"""
:type l1: ListNode
:type l2: ListNode
:rtype: ListNode
"""
l1_n=0
tmp=l1
while tmp!=None:
tmp=tmp.next
l1_n+=1
## 判斷l2的鏈表長度:
l2_n=0
tmp=l2
while tmp!=None:
tmp=tmp.next
l2_n+=1
print l1_n,l2_n
l_num=0
tmp=l1
for i in range(l1_n-1,-1,-1):
print i
l_num+=(10**i) * tmp.val
tmp=tmp.next
tmp=l2
for i in range(l2_n-1,-1,-1):
print i
l_num+=(10**i) * tmp.val
tmp=tmp.next
l_tmp=None
l_num=str(l_num)
for i in range(len(l_num)-1,-1,-1):
print i
l_re=ListNode(l_num[i])
if l_tmp==None:
pass
else :
l_re.next=l_tmp
l_tmp=l_re
return l_re
def addTwoNumbers(self, l1: ListNode, l2: ListNode) -> ListNode:
s1, s2 = [], []
while l1:
s1.append(l1.val)
l1 = l1.next
while l2:
s2.append(l2.val)
l2 = l2.next
ans = None
carry = 0
while s1 or s2 or carry != 0:
a = 0 if not s1 else s1.pop()
b = 0 if not s2 else s2.pop()
cur = a + b + carry
carry = cur // 10
cur %= 10
curnode = ListNode(cur)
curnode.next = ans
ans = curnode
return ans
給定一個由 0 和 1 組成的矩陣,找出每個元素到最近的 0 的距離。
兩個相鄰元素間的距離為 1 。
class Solution(object):
def updateMatrix(self, matrix):
"""
:type matrix: List[List[int]]
:rtype: List[List[int]]
"""
m,n=len(matrix),len(matrix[0])
dp=[[0] * n for _ in range(m)]
print dp
zeros = [(i, j) for i in range(m) for j in range(n) if matrix[i][j] == 0]
print zeros
q=collections.deque(zeros)
seen=set(zeros)
while q:
i,j=q.popleft()
for ni,nj in [(i-1,j),(i,j-1),(i+1,j),(i,j+1)]:
if 0<=ni<m and 0<=nj<n and (ni,nj) not in seen:
dp[ni][nj]=dp[i][j]+1
q.append((ni,nj))
seen.add((ni,nj))
return dp
給出一個區間的集合,請合并所有重疊的區間。
class Solution(object):
def merge(self, intervals):
"""
:type intervals: List[List[int]]
:rtype: List[List[int]]
"""
intervals.sort(key=lambda x :x[0])
merge=[]
for l in intervals:
if not merge or merge[-1][1]<l[0]:
merge.append(l)
else :
merge[-1][1]=max(merge[-1][1],l[1])
return merge
給定一個非負整數數組,你最初位于數組的第一個位置。
數組中的每個元素代表你在該位置可以跳躍的最大長度。
判斷你是否能夠到達最后一個位置。
class Solution(object):
def canJump(self, nums):
"""
:type nums: List[int]
:rtype: bool
"""
n,right=len(nums),0
for i in range(n):
if i<=right:
right=max(right,i+nums[i])
if right>=n-1:
return True
return False
給你 n 個非負整數 a1,a2,...,an,每個數代表坐標中的一個點 (i, ai) 。在坐標內畫 n 條垂直線,垂直線 i 的兩個端點分別為 (i, ai) 和 (i, 0)。找出其中的兩條線,使得它們與 x 軸共同構成的容器可以容納最多的水。
說明:你不能傾斜容器,且 n 的值至少為 2。
class Solution:
def maxArea(self, height: List[int]) -> int:
l, r = 0, len(height) - 1
ans = 0
while l < r:
area = min(height[l], height[r]) * (r - l)
ans = max(ans, area)
if height[l] <= height[r]:
l += 1
else:
r -= 1
return ans
由 n 個連接的字符串 s 組成字符串 S,記作 S = [s,n]。例如,["abc",3]=“abcabcabc”。
如果我們可以從 s2 中刪除某些字符使其變為 s1,則稱字符串 s1 可以從字符串 s2 獲得。例如,根據定義,"abc" 可以從 “abdbec” 獲得,但不能從 “acbbe” 獲得。
現在給你兩個非空字符串 s1 和 s2(每個最多 100 個字符長)和兩個整數 0 ≤ n1 ≤ 106 和 1 ≤ n2 ≤ 106。現在考慮字符串 S1 和 S2,其中 S1=[s1,n1] 、S2=[s2,n2] 。
請你找出一個可以滿足使[S2,M] 從 S1 獲得的最大整數 M 。
class Solution:
def getMaxRepetitions(self, s1: str, n1: int, s2: str, n2: int) -> int:
if n1 == 0:
return 0
s1cnt, index, s2cnt = 0, 0, 0
# recall 是我們用來找循環節的變量,它是一個哈希映射
# 我們如何找循環節?假設我們遍歷了 s1cnt 個 s1,此時匹配到了第 s2cnt 個 s2 中的第 index 個字符
# 如果我們之前遍歷了 s1cnt' 個 s1 時,匹配到的是第 s2cnt' 個 s2 中同樣的第 index 個字符,那么就有循環節了
# 我們用 (s1cnt', s2cnt', index) 和 (s1cnt, s2cnt, index) 表示兩次包含相同 index 的匹配結果
# 那么哈希映射中的鍵就是 index,值就是 (s1cnt', s2cnt') 這個二元組
# 循環節就是;
# - 前 s1cnt' 個 s1 包含了 s2cnt' 個 s2
# - 以后的每 (s1cnt - s1cnt') 個 s1 包含了 (s2cnt - s2cnt') 個 s2
# 那么還會剩下 (n1 - s1cnt') % (s1cnt - s1cnt') 個 s1, 我們對這些與 s2 進行暴力匹配
# 注意 s2 要從第 index 個字符開始匹配
recall = dict()
while True:
# 我們多遍歷一個 s1,看看能不能找到循環節
s1cnt += 1
for ch in s1:
if ch == s2[index]:
index += 1
if index == len(s2):
s2cnt, index = s2cnt + 1, 0
# 還沒有找到循環節,所有的 s1 就用完了
if s1cnt == n1:
return s2cnt // n2
# 出現了之前的 index,表示找到了循環節
if index in recall:
s1cnt_prime, s2cnt_prime = recall[index]
# 前 s1cnt' 個 s1 包含了 s2cnt' 個 s2
pre_loop = (s1cnt_prime, s2cnt_prime)
# 以后的每 (s1cnt - s1cnt') 個 s1 包含了 (s2cnt - s2cnt') 個 s2
in_loop = (s1cnt - s1cnt_prime, s2cnt - s2cnt_prime)
break
else:
recall[index] = (s1cnt, s2cnt)
# ans 存儲的是 S1 包含的 s2 的數量,考慮的之前的 pre_loop 和 in_loop
ans = pre_loop[1] + (n1 - pre_loop[0]) // in_loop[0] * in_loop[1]
# S1 的末尾還剩下一些 s1,我們暴力進行匹配
rest = (n1 - pre_loop[0]) % in_loop[0]
for i in range(rest):
for ch in s1:
if ch == s2[index]:
index += 1
if index == len(s2):
ans, index = ans + 1, 0
# S1 包含 ans 個 s2,那么就包含 ans / n2 個 S2
return ans // n2
給你一個由 '1'(陸地)和 '0'(水)組成的的二維網格,請你計算網格中島嶼的數量。
島嶼總是被水包圍,并且每座島嶼只能由水平方向和/或豎直方向上相鄰的陸地連接形成。
此外,你可以假設該網格的四條邊均被水包圍。
class Solution(object):
def numIslands(self, grid):
"""
:type grid: List[List[str]]
:rtype: int
"""
land_cnt=0
ones=[(i,j) for i in range(len(grid)) for j in range(len(grid[0])) if grid[i][j]=='1']
print ones
seen=set()
while len(ones)!=0:
land_cnt+=1
print 'return'
q=set()
q.add(ones[0])
while len(q)!=0:
one=q.pop()
i=int(one[0])
j=int(one[1])
if (i,j) not in seen:
if 0<=i+1<len(grid) and grid[i+1][j]=='1':
q.add((i+1,j))
if 0<=j+1<len(grid[0]) and grid[i][j+1]=='1':
q.add((i,j+1))
if 0<=i-1<len(grid) and grid[i-1][j]=='1':
q.add((i-1,j))
if 0<=j-1<len(grid[0]) and grid[i][j-1]=='1':
q.add((i,j-1))
seen.add(one)
ones=[i for i in ones if i not in seen]
return land_cnt
深度優先搜索:
把所有遍歷到的1全部標記為0
class Solution:
def dfs(self, grid, r, c):
grid[r][c] = 0
nr, nc = len(grid), len(grid[0])
for x, y in [(r - 1, c), (r + 1, c), (r, c - 1), (r, c + 1)]:
if 0 <= x < nr and 0 <= y < nc and grid[x][y] == "1":
self.dfs(grid, x, y)
def numIslands(self, grid: List[List[str]]) -> int:
nr = len(grid)
if nr == 0:
return 0
nc = len(grid[0])
num_islands = 0
for r in range(nr):
for c in range(nc):
if grid[r][c] == "1":
num_islands += 1
self.dfs(grid, r, c)
return num_islands
廣度優先搜索
class Solution:
def numIslands(self, grid: List[List[str]]) -> int:
nr = len(grid)
if nr == 0:
return 0
nc = len(grid[0])
num_islands = 0
for r in range(nr):
for c in range(nc):
if grid[r][c] == "1":
num_islands += 1
grid[r][c] = "0"
neighbors = collections.deque([(r, c)])
while neighbors:
row, col = neighbors.popleft()
for x, y in [(row - 1, col), (row + 1, col), (row, col - 1), (row, col + 1)]:
if 0 <= x < nr and 0 <= y < nc and grid[x][y] == "1":
neighbors.append((x, y))
grid[x][y] = "0"
return num_islands
給你一個整數數組 nums 和一個整數 k。
如果某個 連續 子數組中恰好有 k 個奇數數字,我們就認為這個子數組是「優美子數組」。
請返回這個數組中「優美子數組」的數目。
class Solution(object):
def numberOfSubarrays(self, nums, k):
"""
:type nums: List[int]
:type k: int
:rtype: int
"""
n = len(nums)
odd = [-1]
ans = 0
for i in range(n):
if nums[i] % 2 == 1:
odd.append(i)
odd.append(n)
print(odd)
for i in range(1, len(odd) - k):
ans += (odd[i] - odd[i - 1]) * (odd[i + k] - odd[i + k - 1])
return ans