煎餅排序
給定數組 A,我們可以對其進行煎餅翻轉:我們選擇一些正整數 k <= A.length,然後反轉 A 的前 k 個元素的順序。我們要執行零次或多次煎餅翻轉(按順序一次接一次地進行)以完成對數組 A 的排序。
返回能使 A 排序的煎餅翻轉操作所對應的 k 值序列。任何將數組排序且翻轉次數在 10 * A.length 範圍內的有效答案都將被判斷爲正確。
示例 1:
輸入:[3,2,4,1]
輸出:[4,2,4,3]
解釋:
我們執行 4 次煎餅翻轉,k 值分別爲 4,2,4,和 3。
初始狀態 A = [3, 2, 4, 1]
第一次翻轉後 (k=4): A = [1, 4, 2, 3]
第二次翻轉後 (k=2): A = [4, 1, 2, 3]
第三次翻轉後 (k=4): A = [3, 2, 1, 4]
第四次翻轉後 (k=3): A = [1, 2, 3, 4],此時已完成排序。
示例 2:
輸入:[1,2,3]
輸出:[]
解釋:
輸入已經排序,因此不需要翻轉任何內容。
請注意,其他可能的答案,如[3,3],也將被接受。
提示:
1 <= A.length <= 100
A[i] 是 [1, 2, …, A.length] 的排列
class Solution(object):
def pancakeSort(self, A):
"""
:type A: List[int]
:rtype: List[int]
"""
def tranv(A,index):#反轉前k個數
k=[]
for i in range(index+1):
k.append(A[i])
for i in range(index+1):
A[i]=k.pop()
return None
n=len(A)
ans=[]
for i in range(n):
if n>1:
index,_=max(enumerate(A[:n]),key=lambda x:x[1])#找到前n個數的最大的索引
if index >0:
tranv(A,index)#前index+1個數反轉
ans.append(index+1)
tranv(A,n-1)
ans.append(n)
n-=1
else:break
return ans
複製帶隨機指針的鏈表
給定一個鏈表,每個節點包含一個額外增加的隨機指針,該指針可以指向鏈表中的任何節點或空節點。
要求返回這個鏈表的 深拷貝。
我們用一個由 n 個節點組成的鏈表來表示輸入/輸出中的鏈表。每個節點用一個 [val, random_index] 表示:
val:一個表示 Node.val 的整數。
random_index:隨機指針指向的節點索引(範圍從 0 到 n-1);如果不指向任何節點,則爲 null 。
示例 1:
輸入:head = [[7,null],[13,0],[11,4],[10,2],[1,0]]
輸出:[[7,null],[13,0],[11,4],[10,2],[1,0]]
示例 2:
輸入:head = [[1,1],[2,1]]
輸出:[[1,1],[2,1]]
示例 3:
輸入:head = [[3,null],[3,0],[3,null]]
輸出:[[3,null],[3,0],[3,null]]
示例 4:
輸入:head = []
輸出:[]
解釋:給定的鏈表爲空(空指針),因此返回 null。
提示:
-10000 <= Node.val <= 10000
Node.random 爲空(null)或指向鏈表中的節點。
節點數目不超過 1000 。
"""
# Definition for a Node.
class Node:
def __init__(self, x, next=None, random=None):
self.val = int(x)
self.next = next
self.random = random
"""
class Solution(object):
def copyRandomList(self, head):
"""
:type head: Node
:rtype: Node
"""
p = head
result = None
pre = None
D = {}
while p != None:
node = Node(p.val, random=p.random)
D[p] = node
if pre != None:
pre.next = node
else:
result = node
pre = node
p = p.next
q = result
while q != None:
if q.random != None:
q.random = D[q.random]
q = q.next
#print(result.val)
return result
最長重複子數組
給兩個整數數組 A 和 B ,返回兩個數組中公共的、長度最長的子數組的長度。
示例 1:
輸入:
A: [1,2,3,2,1]
B: [3,2,1,4,7]
輸出: 3
解釋:
長度最長的公共子數組是 [3, 2, 1]。
說明:
1 <= len(A), len(B) <= 1000
0 <= A[i], B[i] < 100
class Solution(object):
def findLength(self, A, B):
"""
:type A: List[int]
:type B: List[int]
:rtype: int
"""
m = len(A)
n = len(B)
if m>n:
m, n, A, B = n, m, B, A
tmp_list = []
result = 0
# 利用','.join([str(i) for i in B])將B轉化爲字符串且任意兩個元素之間用逗號間隔
str_B = ',' + ','.join([str(i) for i in B]) + ','
#print(type(str_B))
for r in A:
tmp_list.append(str(r))
if ',' + ','.join(tmp_list) + ',' in str_B:
result = max(result, len(tmp_list))
else:
tmp_list = tmp_list[1:]
return result
數組中的第k個最大元素
在未排序的數組中找到第 k 個最大的元素。請注意,你需要找的是數組排序後的第 k 個最大的元素,而不是第 k 個不同的元素。
示例 1:
輸入: [3,2,1,5,6,4] 和 k = 2
輸出: 5
示例 2:
輸入: [3,2,3,1,2,4,5,5,6] 和 k = 4
輸出: 4
說明:
你可以假設 k 總是有效的,且 1 ≤ k ≤ 數組的長度。
import heapq
class Solution(object):
def findKthLargest(self, nums, k):
"""
:type nums: List[int]
:type k: int
:rtype: int
"""
result = heapq.nlargest(k,nums)
return result[-1]
無重複字符的最長子串
給定一個字符串,請你找出其中不含有重複字符的 最長子串 的長度。
示例 1:
輸入: “abcabcbb”
輸出: 3
解釋: 因爲無重複字符的最長子串是 “abc”,所以其長度爲 3。
示例 2:
輸入: “bbbbb”
輸出: 1
解釋: 因爲無重複字符的最長子串是 “b”,所以其長度爲 1。
示例 3:
輸入: “pwwkew”
輸出: 3
解釋: 因爲無重複字符的最長子串是 “wke”,所以其長度爲 3。
請注意,你的答案必須是 子串 的長度,“pwke” 是一個子序列,不是子串。
class Solution(object):
def lengthOfLongestSubstring(self, s):
"""
:type s: str
:rtype: int
"""
'''
if s == '':
return 0
s_list = list(s)
Subs = []
for j in range(1, len(s_list)+1):
for i in range(j-1):
Subs.append(s_list[i:j])
#print(Subs)
Lengest = 1
for i in range(len(Subs)):
L = len(set(Subs[i]))
#print(L)
if L == len(Subs[i]) and L > Lengest:
#print(Subs[i])
Lengest = L
return Lengest
'''
# 哈希集合,記錄每個字符是否出現過
occ = set()
n = len(s)
# 右指針,初始值爲 -1,相當於我們在字符串的左邊界的左側,還沒有開始移動
rk, ans = 0, 0
for i in range(n):
if i != 0:
# 左指針向右移動一格,移除一個字符
occ.remove(s[i - 1])
while rk < n and s[rk] not in occ:
# 不斷地移動右指針
occ.add(s[rk])
rk += 1
# 第 i 到 rk 個字符是一個極長的無重複字符子串
ans = max(ans, rk - i)
return ans
兩個字符串的刪除操作
給定兩個單詞 word1 和 word2,找到使得 word1 和 word2 相同所需的最小步數,每步可以刪除任意一個字符串中的一個字符。
示例:
輸入: “sea”, “eat”
輸出: 2
解釋: 第一步將"sea"變爲"ea",第二步將"eat"變爲"ea"
提示:
給定單詞的長度不超過500。
給定單詞中的字符只含有小寫字母。
class Solution(object):
def minDistance(self, word1, word2):
"""
:type word1: str
:type word2: str
:rtype: int
"""
n, m = len(word1),len(word2)
dp = [[0 for _ in range(m+1)] for _ in range(n+1)]
for i in range(1,n+1):
for j in range(1,m+1):
if word1[i-1] == word2[j-1]:
dp[i][j] = dp[i-1][j-1] + 1
else:
dp[i][j] = max(dp[i-1][j],dp[i][j-1])# 最終回溯到dp[k][k],故跳過k到i和k到j之間的不等部分。
return n+m-2*dp[n][m]
破壞迴文字符串
給你一個迴文字符串 palindrome ,請你將其中 一個 字符用任意小寫英文字母替換,使得結果字符串的字典序最小,且 不是 迴文串。
請你返回結果字符串。如果無法做到,則返回一個空串。
示例 1:
輸入:palindrome = “abccba”
輸出:“aaccba”
示例 2:
輸入:palindrome = “a”
輸出:""
提示:
1 <= palindrome.length <= 1000
palindrome 只包含小寫英文字母。
class Solution(object):
def symmetry(self, L, Len):
if Len == 0:
return False
i = 0
j = Len-1
if Len % 2 == 0:
while i < j:
if L[i] != L[j]:
break
i += 1
j -= 1
else:
while i <= j:
if L[i] != L[j]:
break
i += 1
j -= 1
if i > j:
return True
else: return False
def breakPalindrome(self, palindrome):
"""
:type palindrome: str
:rtype: str
"""
n = len(palindrome)
if n == 1:
return ''
for i in range(n):
if palindrome[i] > 'a':
sub = palindrome[:i]+'a'+palindrome[i+1:]
if not self.symmetry(sub, n):
return sub
if self.symmetry(palindrome, n):
palindrome = palindrome[:-1]+'b'
return palindrome
有效的括號字符串
給定一個只包含三種字符的字符串:( ,) 和 *,寫一個函數來檢驗這個字符串是否爲有效字符串。有效字符串具有如下規則:
任何左括號 ( 必須有相應的右括號 )。
任何右括號 ) 必須有相應的左括號 ( 。
左括號 ( 必須在對應的右括號之前 )。
- 可以被視爲單個右括號 ) ,或單個左括號 ( ,或一個空字符串。
一個空字符串也被視爲有效字符串。
示例 1:
輸入: “()”
輸出: True
示例 2:
輸入: “(*)”
輸出: True
示例 3:
輸入: “(*))”
輸出: True
注意:
字符串大小將在 [1,100] 範圍內。
class Solution(object):
def checkValidString(self, s):
"""
:type s: str
:rtype: bool
"""
stack = [] #第一個棧用來記錄所有(的index
star_stack = [] #第二個棧用來記錄所有*的index
for i in range(len(s)):
if s[i] == "(":
stack.append(i)
elif s[i] == "*":
star_stack.append(i)
else:
if not stack and not star_stack:
return False #如果直接讀到),直接return False
if stack:
stack.pop()
elif star_stack:
star_stack.pop() #先用(來消),再用*來消)
while stack and star_stack:
if stack.pop() > star_stack.pop(): #在所有)都處理了之後,只需要考慮(和*的index,此時的*全部當作)來考慮,比較index即可
return False
return not stack #判斷是否有多餘的(
最大加號標誌
(第一次寫思路,有錯誤望指正)
動態規劃:
因爲判斷是否形成加法標誌需要上下左右四個臂的長度,所以不能單一的變量表示不了這個狀態;
我這邊是用四個變量表示狀態,分別爲上下左右的連續臂展長度;
上左狀態變量在正序遍歷數組的時候確定,下右狀態變量用逆序遍歷數組的時候確定;
狀態轉移方程爲 dp[i+1][j+1][0]=dp[i][j+1][0]+1 (上狀態);
最後加法的階數爲四個狀態中最下的那個確定;
class Solution:
def orderOfLargestPlusSign(self, N: int, mines: List[List[int]]) -> int:
l=[[1 for _ in range(N)] for _ in range(N)]
for i in mines:
l[i[0]][i[1]]=0
# 四個位置分別記錄上左下右四個方向上的1的個數,且dp[i+1][j+1]記錄的是以[i,j]爲中心點。
dp = [[[0,0,0,0] for _ in range(N+2)] for _ in range(N+2)]
for i in range(N): #先正向遍歷
for j in range(N):
if l[i][j]==0:
continue
else:
dp[i+1][j+1][0]=dp[i][j+1][0]+1
dp[i+1][j+1][1]=dp[i+1][j][1]+1
for i in range(N-1,-1,-1):
for j in range(N-1,-1,-1): #逆向遍歷
if l[i][j]==0:
continue
else:
dp[i + 1][j + 1][2] = dp[i+2][j + 1][2]+1
dp[i + 1][j + 1][3] = dp[i + 1][j+2][3]+1
m=max([max([min(i) for i in j]) for j in dp])
return m
三數之和
給你一個包含 n 個整數的數組 nums,判斷 nums 中是否存在三個元素 a,b,c ,使得 a + b + c = 0 ?請你找出所有滿足條件且不重複的三元組。
注意:答案中不可以包含重複的三元組。
示例:
給定數組 nums = [-1, 0, 1, 2, -1, -4],
滿足要求的三元組集合爲:
[
[-1, 0, 1],
[-1, -1, 2]
]
class Solution(object):
def threeSum(self, nums):
"""
:type nums: List[int]
:rtype: List[List[int]]
"""
n=len(nums)
res=[]
if(not nums or n<3):
return []
nums.sort()
res=[]
for i in range(n):
if(nums[i]>0):
return res
if(i>0 and nums[i]==nums[i-1]):
continue
L=i+1
R=n-1
while(L<R):
if(nums[i]+nums[L]+nums[R]==0):
res.append([nums[i],nums[L],nums[R]])
while(L<R and nums[L]==nums[L+1]):
L=L+1
while(L<R and nums[R]==nums[R-1]):
R=R-1
L=L+1
R=R-1
elif(nums[i]+nums[L]+nums[R]>0):
R=R-1
else:
L=L+1
return res
分數排名
編寫一個 SQL 查詢來實現分數排名。
如果兩個分數相同,則兩個分數排名(Rank)相同。請注意,平分後的下一個名次應該是下一個連續的整數值。換句話說,名次之間不應該有“間隔”。
±—±------+
| Id | Score |
±—±------+
| 1 | 3.50 |
| 2 | 3.65 |
| 3 | 4.00 |
| 4 | 3.85 |
| 5 | 4.00 |
| 6 | 3.65 |
±—±------+
例如,根據上述給定的 Scores 表,你的查詢應該返回(按分數從高到低排列):
±------±-----+
| Score | Rank |
±------±-----+
| 4.00 | 1 |
| 4.00 | 1 |
| 3.85 | 2 |
| 3.65 | 3 |
| 3.65 | 3 |
| 3.50 | 4 |
±------±-----+
select Score, dense_rank() over (order by Score desc) as `Rank`
from Scores;
字母位移
有一個由小寫字母組成的字符串 S,和一個整數數組 shifts。
我們將字母表中的下一個字母稱爲原字母的 移位(由於字母表是環繞的, ‘z’ 將會變成 ‘a’)。
例如·,shift(‘a’) = ‘b’, shift(‘t’) = ‘u’,, 以及 shift(‘z’) = ‘a’。
對於每個 shifts[i] = x , 我們會將 S 中的前 i+1 個字母移位 x 次。
返回將所有這些移位都應用到 S 後最終得到的字符串。
示例:
輸入:S = “abc”, shifts = [3,5,9]
輸出:“rpl”
解釋:
我們以 “abc” 開始。
將 S 中的第 1 個字母移位 3 次後,我們得到 “dbc”。
再將 S 中的前 2 個字母移位 5 次後,我們得到 “igc”。
最後將 S 中的這 3 個字母移位 9 次後,我們得到答案 “rpl”。
提示:
1 <= S.length = shifts.length <= 20000
0 <= shifts[i] <= 10 ^ 9
import numpy as np
class Solution(object):
def shiftingLetters(self, S, shifts):
"""
:type S: str
:type shifts: List[int]
:rtype: str
"""
'''動態規劃法
m = len(S)
n = len(shifts)
if n > m:
return
S = list(S)
# dp[j][i] 表示第j次位移後S[i]的值
dp = [[S[i] for i in range(n)] for j in range(n)]
for j in range(1, n+1):
for i in range(j):
if j == 1:
dp[j-1][i] = chr((ord(dp[j-1][i]) - 97 + shifts[j-1]) % 26 + 97)
#print(dp[0])
else:
dp[j-1][i] = chr((ord(dp[j-2][i]) - 97 + shifts[j-1]) % 26 + 97)
if m == n:
return ''.join(dp[-1][:])
return ''.join(dp[-1][:]) + ''.join(S[n+1])
'''
res=[]
total=sum(shifts)
for i in range(len(S)):
x=(ord(S[i])+total-97)%26+97
res.append(chr(x))
total-=shifts[i]
return ''.join(res)
索引處的解碼字符串
給定一個編碼字符串 S。爲了找出解碼字符串並將其寫入磁帶,從編碼字符串中每次讀取一個字符,並採取以下步驟:
如果所讀的字符是字母,則將該字母寫在磁帶上。
如果所讀的字符是數字(例如 d),則整個當前磁帶總共會被重複寫 d-1 次。
現在,對於給定的編碼字符串 S 和索引 K,查找並返回解碼字符串中的第 K 個字母。
示例 1:
輸入:S = “leet2code3”, K = 10
輸出:“o”
解釋:
解碼後的字符串爲 “leetleetcodeleetleetcodeleetleetcode”。
字符串中的第 10 個字母是 “o”。
示例 2:
輸入:S = “ha22”, K = 5
輸出:“h”
解釋:
解碼後的字符串爲 “hahahaha”。第 5 個字母是 “h”。
示例 3:
輸入:S = “a2345678999999999999999”, K = 1
輸出:“a”
解釋:
解碼後的字符串爲 “a” 重複 8301530446056247680 次。第 1 個字母是 “a”。
提示:
2 <= S.length <= 100
S 只包含小寫字母與數字 2 到 9 。
S 以字母開頭。
1 <= K <= 10^9
解碼後的字符串保證少於 2^63 個字母。
思路:
如果S=‘vk3u5xhq2v’, 這種時候需要找到每一個操作的原始和解碼字符索引, 記爲(x, y), x表示decode(S)中的位置(從1開始計算), y表示S中的位置(從0開始計算)
最終的字符爲’vkuxhqv’
索引記錄表對應的就是[v(1,0), k(2,1), 3(6,1), u(7,2), 5(35,2), x(36,3), h(37,4), q(38,5), 2(76,5), v(77,6)]
可以根據K值提前結束索引記錄過程, 比如假設K=50, 上面的S在2(76,5)的時候由於76>=50, 跳出循環
然後開始逆向找K對應的應該是原始S中的哪個字符, 類似於進制轉換, 把K與每個decode(S)取餘, 結果爲0的時候說明答案就是對應操作中的原始位置.
class Solution(object):
def decodeAtIndex(self, S, K):
"""
:type S: str
:type K: int
:rtype: str
"""
i = cnt = 0
c = ''
x = []# x[i] = [解碼後的位置(從1開始),解碼前的位置(從0開始)]
while i < len(S) and cnt < K:
if S[i].isdigit():# S[i]是數字
cnt *= int(S[i])
if S[i-1].isdigit(): x[-1][0] = cnt# 若上一個也是數字,則修改上一次的解碼後位置。
else: x.append([cnt, len(c) - 1])# 若上一個不是數字,則記錄這次的位置。即上一個字母經過複製在當下的位置。
else:# S[i]是字母
c += S[i]
cnt += 1
x.append([cnt, len(c) - 1])
i += 1
ret = ''
while x:
t = x.pop()
K %= t[0]
if K == 0:
ret = c[t[1]]
break
return ret
模式匹配
你有兩個字符串,即pattern和value。 pattern字符串由字母"a"和"b"組成,用於描述字符串中的模式。例如,字符串"catcatgocatgo"匹配模式"aabab"(其中"cat"是"a",“go"是"b”),該字符串也匹配像"a"、"ab"和"b"這樣的模式。但需注意"a"和"b"不能同時表示相同的字符串。編寫一個方法判斷value字符串是否匹配pattern字符串。
示例 1:
輸入: pattern = “abba”, value = “dogcatcatdog”
輸出: true
示例 2:
輸入: pattern = “abba”, value = “dogcatcatfish”
輸出: false
示例 3:
輸入: pattern = “aaaa”, value = “dogcatcatdog”
輸出: false
示例 4:
輸入: pattern = “abba”, value = “dogdogdogdog”
輸出: true
解釋: “a”=“dogdog”,b="",反之也符合規則
提示:
0 <= len(pattern) <= 1000
0 <= len(value) <= 1000
你可以假設pattern只包含字母"a"和"b",value僅包含小寫字母。
思路:
存在以下幾種情況:
1)pattern和value都爲空,返回True
2)僅pattern爲空: 返回False
3)僅value爲空,這時候分兩種情況:如果pattern中只存在a或者b一種,那麼令a或者b爲空,符合條件,返回True;否則,由於不同pattern不能表示同一字符串,返回False
4)都不爲空的情況下:如果pattern中只有a或者b一種,那意味這value全由一種字符串構成。它需滿足以下兩個條件:首先,value的長度需要被pattern的長度整除;其次,value中的每一個字符串需要都是a,根據value長度和pattern長度很容易計算出a的長度,然後順次取出看是否相同即可。
5)如果pattern中同時含有a和b,也有兩種情況。第一種,其中一個pattern只有一個,假設a只有一個,那麼只需要令a= value, b=“”,即可,所以直接返回True
6)另一種情況,同時含有a, b且個數都大於1。這時候,我們先統計pattern中a, b各有多少個,然後遍歷a的所有可能長度,對於某個確定的a的長度,結合a的個數和b的個數以及value的長度,我們即可以確定b的長度。這時候需要滿足以下條件:首先b的長度也必須是整數;其次,value只能由a, b結合而成。
class Solution(object):
def patternMatching(self, pattern, value):
"""
:type pattern: str
:type value: str
:rtype: bool
"""
if not value and not pattern: return True
if not pattern: return False
if not value:
if len(pattern)==1: return True
else: return False
if len(set(pattern))==1: # 如果只有一種pattern
if len(value)%len(pattern)!=0:
return False
length = len(value) // len(pattern)
return all([value[i:i+length]==value[0:length] for i in range(0, len(value),length)])
if pattern.count('a')==1 or pattern.count('b')==1:# 兩種pattern但是其中一種只有一個,只需要另這個爲value,另外一個爲空即可
return True
cnt_a = pattern.count('a')
cnt_b = pattern.count('b')
for i in range(len(value)//cnt_a): # 遍歷a的所有可能長度
remain = len(value) - i * cnt_a
if remain % cnt_b != 0:
continue
j = remain // cnt_b
set_a = set()
set_b = set()
p = 0
for s in pattern:
if s=='a':
set_a.add(value[p:p+i])
p += i
else:
set_b.add(value[p:p+j])
p += j
if len(set_a)==len(set_b)==1:
return True
return False
二倍數對數組
給定一個長度爲偶數的整數數組 A,只有對 A 進行重組後可以滿足 “對於每個 0 <= i < len(A) / 2,都有 A[2 * i + 1] = 2 * A[2 * i]” 時,返回 true;否則,返回 false。
示例 1:
輸入:[3,1,3,6]
輸出:false
示例 2:
輸入:[2,1,2,6]
輸出:false
示例 3:
輸入:[4,-2,2,-4]
輸出:true
解釋:我們可以用 [-2,-4] 和 [2,4] 這兩組組成 [-2,-4,2,4] 或是 [2,4,-2,-4]
示例 4:
輸入:[1,2,4,16,8,4]
輸出:false
提示:
0 <= A.length <= 30000
A.length 爲偶數
-100000 <= A[i] <= 100000
from collections import Counter
class Solution(object):
def canReorderDoubled(self, A):
"""
:type A: List[int]
:rtype: bool
"""
count = Counter(A)#對於不存在的key,count[key]=0
# 注意是對count進行排序
# sorted(count, key=abs)等價於sorted(count.keys(),key = abs)
for i in sorted(count, key=abs):
if count[i] > count[i*2]:
return False
count[i*2] -= count[i]
return True
鏈表隨機節點
給定一個單鏈表,隨機選擇鏈表的一個節點,並返回相應的節點值。保證每個節點被選的概率一樣。
進階:
如果鏈表十分大且長度未知,如何解決這個問題?你能否使用常數級空間複雜度實現?
示例:
// 初始化一個單鏈表 [1,2,3].
ListNode head = new ListNode(1);
head.next = new ListNode(2);
head.next.next = new ListNode(3);
Solution solution = new Solution(head);
// getRandom()方法應隨機返回1,2,3中的一個,保證每個元素被返回的概率相等。
solution.getRandom();
# Definition for singly-linked list.
# class ListNode(object):
# def __init__(self, x):
# self.val = x
# self.next = None
import random
class Solution(object):
def __init__(self, head):
"""
@param head The linked list's head.
Note that the head is guaranteed to be not null, so it contains at least one node.
:type head: ListNode
"""
assert head is not None
self.head = head
self.length = self.Length()
def Length(self):
p = self.head
L = 0
while p != None:
L += 1
p = p.next
return L
def getRandom(self):
"""
Returns a random node's value.
:rtype: int
"""
k = random.randint(0, self.length-1)
#print(k)
p = self.head
L = 0
while p != None:
if L == k:
break
L += 1
p = p.next
if p == None:
print(k, self.length)
return p.val
# Your Solution object will be instantiated and called as such:
# obj = Solution(head)
# param_1 = obj.getRandom()
有序數組中的單一元素
給定一個只包含整數的有序數組,每個元素都會出現兩次,唯有一個數只會出現一次,找出這個數。
示例 1:
輸入: [1,1,2,3,3,4,4,8,8]
輸出: 2
示例 2:
輸入: [3,3,7,7,10,11,11]
輸出: 10
注意: 您的方案應該在 O(log n)時間複雜度和 O(1)空間複雜度中運行。
import collections
class Solution(object):
def singleNonDuplicate(self, nums):
"""
:type nums: List[int]
:rtype: int
"""
count = collections.Counter(nums)
result = 0
for key, value in count.items():
if value == 1:
result = key
return result
等差數列劃分
如果一個數列至少有三個元素,並且任意兩個相鄰元素之差相同,則稱該數列爲等差數列。
例如,以下數列爲等差數列:
1, 3, 5, 7, 9
7, 7, 7, 7
3, -1, -5, -9
以下數列不是等差數列。
1, 1, 2, 5, 7
數組 A 包含 N 個數,且索引從0開始。數組 A 的一個子數組劃分爲數組 (P, Q),P 與 Q 是整數且滿足 0<=P<Q<N 。
如果滿足以下條件,則稱子數組(P, Q)爲等差數組:
元素 A[P], A[p + 1], …, A[Q - 1], A[Q] 是等差的。並且 P + 1 < Q 。
函數要返回數組 A 中所有爲等差數組的子數組個數。
示例:
A = [1, 2, 3, 4]
返回: 3, A 中有三個子等差數組: [1, 2, 3], [2, 3, 4] 以及自身 [1, 2, 3, 4]。
思路:
首先遍歷原數組 nums,用數組 diffs 存儲相鄰兩個元素之間的差值。
然後遍歷 diffs,用數組 cons 存儲其中連續相同的差值的數目,比如有 33 個 33 連在一起,意味着原數組中這個位置存在一個最大長度爲 44 的等差數列。
然後遍歷 cons,對於長度爲 n 的等差數列,其所有的長度大於等於 33 的子數列都是等差數列,則一共有 (n-2)(n-1)/2 個等差數列。
全部相加得到結果。
比如:
nums = [1,2,3,4,5,6,12,14,16]
diffs = [1,1,1,1,1,6,2,2]
cons = [5,1,2]
將 1 捨去,nums 中有長度爲 5+1 和 2+1 的等差數列
result = (6-2)(6-1)/2 + (3-2)(3-1)/2
class Solution(object):
def numberOfArithmeticSlices(self, nums):
"""
:type nums: List[int]
:rtype: int
"""
# 第一次遍歷
diffs = []
for i in range(len(nums) - 1):
diffs.append(nums[i + 1] - nums[i])
# 第二次遍歷
cons = []
a = 1
for i in range(1, len(diffs)):
if diffs[i] == diffs[i - 1]:
a += 1
else:
cons.append(a)
a = 1
cons.append(a)
# 第三次遍歷
res = 0
for num in cons:
res += int(self.calc(num))
return res
# 用於計算cons內每個數代表的等差數列個數
def calc(self, n):
if n == 1:
return 0
n += 1
return (n-2)*(n-1)/2
最長迴文子串(連續子串)
給定一個字符串 s,找到 s 中最長的迴文子串。你可以假設 s 的最大長度爲 1000。
示例 1:
輸入: “babad”
輸出: “bab”
注意: “aba” 也是一個有效答案。
示例 2:
輸入: “cbbd”
輸出: “bb”
class Solution(object):
def longestPalindrome(self, s):
"""
:type s: str
:rtype: str
"""
n = len(s)
dp = [[False for j in range(n)] for i in range(n)]
begin_idx = 0
MaxL = 0
for j in range(n):
for i in range(j+1):
L = j - i + 1
if s[i] == s[j]:
if L <= 3:
dp[i][j] = True
else:
dp[i][j] = dp[i+1][j-1]
if dp[i][j] and L > MaxL:
#print(i, j)
begin_idx = i
MaxL = L
#print(dp)
return s[begin_idx:begin_idx+MaxL]
最長迴文子串(不連續)
給定一個字符串s,找到其中最長的迴文子序列,並返回該序列的長度。可以假設s的最大長度爲1000。
示例 1:
輸入:
“bbbab”
輸出:
4
一個可能的最長迴文子序列爲 “bbbb”。
示例 2:
輸入:
“cbbd”
輸出:
2
一個可能的最長迴文子序列爲 “bb”。
class Solution(object):
def longestPalindromeSubseq(self, s):
"""
:type s: str
:rtype: int
"""
# 使用dp思想
n = len(s)
dp = [[0]*n for i in range(n)]
# 注意basecase
for i in range(n):
dp[i][i] = 1
# 倒着遍歷
for i in range(n-2,-1,-1):
for j in range(i+1,n):
if s[i] == s[j]:
dp[i][j] = dp[i+1][j-1] + 2
else:
dp[i][j] = max(dp[i+1][j],dp[i][j-1])
return dp[0][n-1]
搜索旋轉排序數組
假設按照升序排序的數組在預先未知的某個點上進行了旋轉。
( 例如,數組 [0,1,2,4,5,6,7] 可能變爲 [4,5,6,7,0,1,2] )。
搜索一個給定的目標值,如果數組中存在這個目標值,則返回它的索引,否則返回 -1 。
你可以假設數組中不存在重複的元素。
你的算法時間複雜度必須是 O(log n) 級別。
示例 1:
輸入: nums = [4,5,6,7,0,1,2], target = 0
輸出: 4
示例 2:
輸入: nums = [4,5,6,7,0,1,2], target = 3
輸出: -1
思路:分成兩段,分別進行二分查找,平均時間複雜度O(logn)
各種查找和排序算法的時間和空間複雜度
class Solution(object):
def BinarySearch(self, nums, start, end, target, n):
if end < 0 or start > n-1 or (start == end and nums[start] != target) or end < start:
return -1
mid = (start + end) // 2
if nums[mid] == target:
return mid
elif nums[mid] > target:
return self.BinarySearch(nums, start, mid-1, target, n)
else:
return self.BinarySearch(nums, mid+1, end, target, n)
def search(self, nums, target):
"""
:type nums: List[int]
:type target: int
:rtype: int
"""
boundary = 0
n = len(nums)
for i in range(n-1):
if nums[i] > nums[i+1]:
boundary = i+1
answer1 = self.BinarySearch(nums, 0, boundary, target, n)
answer2 = self.BinarySearch(nums, boundary, n, target, n)
if answer1 == answer2 == -1:
return -1
elif answer1 != -1:
return answer1
else:
return answer2
分隔數組以得到最大和
給出整數數組 A,將該數組分隔爲長度最多爲 K 的幾個(連續)子數組。分隔完成後,每個子數組的中的值都會變爲該子數組中的最大值。
返回給定數組完成分隔後的最大和。
示例:
輸入:A = [1,15,7,9,2,5,10], K = 3
輸出:84
解釋:A 變爲 [15,15,15,9,10,10,10]
提示:
1 <= K <= A.length <= 500
0 <= A[i] <= 10^6
思路:動態規劃
class Solution(object):
def maxSumAfterPartitioning(self, A, K):
"""
:type A: List[int]
:type K: int
:rtype: int
"""
n=len(A)
res=[0]*(n+1)
for i in range(1,n+1) :
j=i-1
mx=float("-inf")
while i-j <= K and j >= 0 :
#由於不知道lastSubA的大小,因此對lastSubA的所有可能都進行計算,取最大的
mx=max(mx,A[j])
res[i]=max(res[i],res[j]+mx*(i-j))
j-=1
return res[n]
擺動排序
給你一個無序的數組 nums, 將該數字 原地 重排後使得 nums[0] <= nums[1] >= nums[2] <= nums[3]…。
示例:
輸入: nums = [3,5,2,1,6,4]
輸出: 一個可能的解答是 [3,5,1,6,2,4]
from heapq import *
class Solution(object):
def wiggleSort(self, nums):
"""
:type nums: List[int]
:rtype: None Do not return anything, modify nums in-place instead.
"""
n = len(nums)
if n <= 1:
return nums
a = n // 2
new_nums = zip(nums, [i for i in range(n)])
lar = nlargest(a, new_nums)
laridx = [t[1] for t in lar]
#print(lar)
smal = [nums[t] for t in range(n) if t not in laridx]
lar = [nums[m] for m in laridx]
nums[1:n:2] = lar
nums[0:n:2] = smal
return nums
排序鏈表
在 O(n log n) 時間複雜度和常數級空間複雜度下,對鏈表進行排序。
示例 1:
輸入: 4->2->1->3
輸出: 1->2->3->4
示例 2:
輸入: -1->5->3->4->0
輸出: -1->0->3->4->5
思路:
解答一:歸併排序(遞歸法)
題目要求時間空間複雜度分別爲O(nlogn)O(nlogn)和O(1)O(1),根據時間複雜度我們自然想到二分法,從而聯想到歸併排序;
對數組做歸併排序的空間複雜度爲 O(n)O(n),分別由新開闢數組O(n)O(n)和遞歸函數調用O(logn)O(logn)組成,而根據鏈表特性:
數組額外空間:鏈表可以通過修改引用來更改節點順序,無需像數組一樣開闢額外空間;
遞歸額外空間:遞歸調用函數將帶來O(logn)O(logn)的空間複雜度,因此若希望達到O(1)O(1)空間複雜度,則不能使用遞歸。
通過遞歸實現鏈表歸併排序,有以下兩個環節:
分割 cut 環節: 找到當前鏈表中點,並從中點將鏈表斷開(以便在下次遞歸 cut 時,鏈表片段擁有正確邊界);
我們使用 fast,slow 快慢雙指針法,奇數個節點找到中點,偶數個節點找到中心左邊的節點。
找到中點 slow 後,執行 slow.next = None 將鏈表切斷。
遞歸分割時,輸入當前鏈表左端點 head 和中心節點 slow 的下一個節點 tmp(因爲鏈表是從 slow 切斷的)。
cut 遞歸終止條件: 當head.next == None時,說明只有一個節點了,直接返回此節點。
合併 merge 環節: 將兩個排序鏈表合併,轉化爲一個排序鏈表。
雙指針法合併,建立輔助ListNode h 作爲頭部。
設置兩指針 left, right 分別指向兩鏈表頭部,比較兩指針處節點值大小,由小到大加入合併鏈表頭部,指針交替前進,直至添加完兩個鏈表。
返回輔助ListNode h 作爲頭部的下個節點 h.next。
時間複雜度 O(l + r),l, r 分別代表兩個鏈表長度。
當題目輸入的 head == None 時,直接返回None。
# Definition for singly-linked list.
# class ListNode(object):
# def __init__(self, x):
# self.val = x
# self.next = None
class Solution(object):
def sortList(self, head):
"""
:type head: ListNode
:rtype: ListNode
"""
if not head or not head.next: return head # termination.
# cut the LinkedList at the mid index.
slow, fast = head, head.next
while fast and fast.next:
fast, slow = fast.next.next, slow.next
mid, slow.next = slow.next, None # save and cut.
# recursive for cutting.
left, right = self.sortList(head), self.sortList(mid)
# merge `left` and `right` linked list and return it.
h = res = ListNode(0)
while left and right:
if left.val < right.val: h.next, left = left, left.next
else: h.next, right = right, right.next
h = h.next
h.next = left if left else right
return res.next
島嶼的最大面積
給定一個包含了一些 0 和 1 的非空二維數組 grid 。
一個 島嶼 是由一些相鄰的 1 (代表土地) 構成的組合,這裏的「相鄰」要求兩個 1 必須在水平或者豎直方向上相鄰。你可以假設 grid 的四個邊緣都被 0(代表水)包圍着。
找到給定的二維數組中最大的島嶼面積。(如果沒有島嶼,則返回面積爲 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。
注意: 給定的矩陣grid 的長度和寬度都不超過 50。
class Solution(object):
def maxAreaOfIsland(self, grid):
"""
:type grid: List[List[int]]
:rtype: int
"""
m = len(grid)
if m == 0: return 0
n = len(grid[0])
ans = 0
def dfs(i, j):
if i < 0 or i >= m or j < 0 or j >= n: return 0
if grid[i][j] == 0: return 0
grid[i][j] = 0
top = dfs(i + 1, j)
bottom = dfs(i - 1, j)
left = dfs(i, j - 1)
right = dfs(i, j + 1)
return 1 + sum([top, bottom, left, right])
for i in range(m):
for j in range(n):
ans = max(ans, dfs(i, j))
return ans
合併區間
給出一個區間的集合,請合併所有重疊的區間。
示例 1:
輸入: [[1,3],[2,6],[8,10],[15,18]]
輸出: [[1,6],[8,10],[15,18]]
解釋: 區間 [1,3] 和 [2,6] 重疊, 將它們合併爲 [1,6].
示例 2:
輸入: [[1,4],[4,5]]
輸出: [[1,5]]
解釋: 區間 [1,4] 和 [4,5] 可被視爲重疊區間。
class Solution(object):
def merge(self, intervals):
"""
:type intervals: List[List[int]]
:rtype: List[List[int]]
"""
intervals.sort()
m = len(intervals)
i = 0
while i < m-1:
if intervals[i][1] >= intervals[i+1][0]:
# 合併區間
intervals[i][1] = max(intervals[i][1], intervals[i+1][1])
del intervals[i+1]
m -= 1
else:
i += 1
return intervals
整數替換
給定一個正整數 n,你可以做如下操作:
- 如果 n 是偶數,則用 n / 2替換 n。
- 如果 n 是奇數,則可以用 n + 1或n - 1替換 n。
n 變爲 1 所需的最小替換次數是多少?
示例 1:
輸入:
8
輸出:
3
解釋:
8 -> 4 -> 2 -> 1
示例 2:
輸入:
7
輸出:
4
解釋:
7 -> 8 -> 4 -> 2 -> 1
或
7 -> 6 -> 3 -> 2 -> 1
思路:每遇偶數除以2,沒什麼好說。
遇到奇數,應變換使其成爲4的倍數,目的是使該數下一步變成能連續兩次除以2的偶數
因此mod41時減1,mod43時加1
有個例外是3, 3——2——1 比 3——4——2——1更快
class Solution(object):
def integerReplacement(self, n):
"""
:type n: int
:rtype: int
"""
count = 0
while n>1:
if n==3:
n-=1
elif n%4==1:
n-=1
elif n%4==3:
n+=1
else:
n/=2
count+=1
return count
分割數組
給定一個數組 A,將其劃分爲兩個不相交(沒有公共元素)的連續子數組 left 和 right, 使得:
left 中的每個元素都小於或等於 right 中的每個元素。
left 和 right 都是非空的。
left 要儘可能小。
在完成這樣的分組後返回 left 的長度。可以保證存在這樣的劃分方法。
示例 1:
輸入:[5,0,3,8,6]
輸出:3
解釋:left = [5,0,3],right = [8,6]
示例 2:
輸入:[1,1,1,0,6,12]
輸出:4
解釋:left = [1,1,1,0],right = [6,12]
提示:
2 <= A.length <= 30000
0 <= A[i] <= 10^6
可以保證至少有一種方法能夠按題目所描述的那樣對 A 進行劃分。
class Solution(object):
def partitionDisjoint(self, A):
"""
:type A: List[int]
:rtype: int
"""
tmp,pos,m = A[0],0,A[0]
for i in range(1,len(A)):
m = max(m,A[i])
if A[i]<tmp:
pos = i
tmp = m
return pos+1
從英文中重建數字
給定一個非空字符串,其中包含字母順序打亂的英文單詞表示的數字0-9。按升序輸出原始的數字。
注意:
輸入只包含小寫英文字母。
輸入保證合法並可以轉換爲原始的數字,這意味着像 “abc” 或 “zerone” 的輸入是不允許的。
輸入字符串的長度小於 50,000。
示例 1:
輸入: “owoztneoer”
輸出: “012” (zeroonetwo)
示例 2:
輸入: “fviefuro”
輸出: “45” (fourfive)
class Solution(object):
def originalDigits(self, s):
"""
:type s: str
:rtype: str
"""
res = {}
for i in s:
if res.get(i):
res[i] += 1
else:
res[i] = 1
if res.get('z'): #0 : z
res['r'] -= res['z']
res['o'] -= res['z']
if res.get('w'): #2 : w
res['t'] -= res['w']
res['o'] -= res['w']
if res.get('u'): #4 : u; 1 : o; 3 : r; 5 : f;
res['f'] -= res['u']
res['o'] -= res['u']
res['r'] -= res['u']
if res.get('o') and res['o'] > 0:
res['n'] -= res['o']
if res.get('f') and res['f'] > 0: #7 : v
res['v'] -= res['f']
if res.get('r') and res['r'] > 0: #8 : t
res['t'] -= res['r']
if res.get('v') and res['v'] > 0: #6 : s; 9 : n
res['s'] -= res['v']
res['n'] -= res['v']
num = ''
if res.get('z'):
num += '0'*res['z']
if res.get('o'):
num += '1'*res['o']
if res.get('w'):
num += '2'*res['w']
if res.get('r'):
num += '3'*res['r']
if res.get('u'):
num += '4'*res['u']
if res.get('f'):
num += '5'*res['f']
if res.get('s'):
num += '6'*res['s']
if res.get('v'):
num += '7'*res['v']
if res.get('t'):
num += '8'*res['t']
if res.get('n'):
num += '9'*(res['n']//2)
return num
克隆圖
給你無向 連通 圖中一個節點的引用,請你返回該圖的 深拷貝(克隆)。
圖中的每個節點都包含它的值 val(int) 和其鄰居的列表(list[Node])。
class Node {
public int val;
public List neighbors;
}
測試用例格式:
簡單起見,每個節點的值都和它的索引相同。例如,第一個節點值爲 1(val = 1),第二個節點值爲 2(val = 2),以此類推。該圖在測試用例中使用鄰接列表表示。
鄰接列表 是用於表示有限圖的無序列表的集合。每個列表都描述了圖中節點的鄰居集。
給定節點將始終是圖中的第一個節點(值爲 1)。你必須將 給定節點的拷貝 作爲對克隆圖的引用返回。
示例 1:
輸入:adjList = [[2,4],[1,3],[2,4],[1,3]]
輸出:[[2,4],[1,3],[2,4],[1,3]]
解釋:
圖中有 4 個節點。
節點 1 的值是 1,它有兩個鄰居:節點 2 和 4 。
節點 2 的值是 2,它有兩個鄰居:節點 1 和 3 。
節點 3 的值是 3,它有兩個鄰居:節點 2 和 4 。
節點 4 的值是 4,它有兩個鄰居:節點 1 和 3 。
示例 2:
輸入:adjList = [[]]
輸出:[[]]
解釋:輸入包含一個空列表。該圖僅僅只有一個值爲 1 的節點,它沒有任何鄰居。
示例 3:
輸入:adjList = []
輸出:[]
解釋:這個圖是空的,它不含任何節點。
示例 4:
輸入:adjList = [[2],[1]]
輸出:[[2],[1]]
提示:
節點數不超過 100 。
每個節點值 Node.val 都是唯一的,1 <= Node.val <= 100。
無向圖是一個簡單圖,這意味着圖中沒有重複的邊,也沒有自環。
由於圖是無向的,如果節點 p 是節點 q 的鄰居,那麼節點 q 也必須是節點 p 的鄰居。
圖是連通圖,你可以從給定節點訪問到所有節點。
"""
# Definition for a Node.
class Node(object):
def __init__(self, val = 0, neighbors = []):
self.val = val
self.neighbors = neighbors
"""
class Solution(object):
def cloneGraph(self, node):
"""
:type node: Node
:rtype: Node
"""
lookup = {}
def dfs(node):
#print(node.val)
if not node: return
if node in lookup:
return lookup[node]
clone = Node(node.val, [])
lookup[node] = clone
for n in node.neighbors:
clone.neighbors.append(dfs(n))
return clone
return dfs(node)