leetcode探索專題中的初級演算法練習題(python程式碼+解題思路)
本文記錄leetcode探索專題中的初級演算法練習題,附python實現程式碼&解題思路,做題過程不免查閱網路資料,侵刪~如有錯誤,歡迎指正交流!
目錄
專題一:陣列:
26.從排序陣列中刪除重複項
給定1個排序陣列,你需要在原地刪除重複出現的元素,使得每個元素只出現1次,返回移除後陣列的新長度。
不需要使用額外的陣列空間,你必須在原地修改輸入陣列並在使用O(1)額外空間的條件下完成。
說明:為什麼返回數值是整數,但輸出的答案是陣列呢
注意:輸入陣列是以“引用”方式傳遞的,這意味著在函式裡修改輸入陣列對於呼叫者是可見的。
你可以想象內部操作如下:
//nums是以“引用”方式傳播的,也就是說,不對實參做任何拷貝
int len = removeDuplicates(nums);
思路:只不過這道題的難度在於,在操作中不能隨意改變陣列中原本元素的位置,因為你要保持它後面的數字還是有序的,才好去比較相鄰的數字是否一樣。
因此,我們弄1個變數記錄上1個單獨的數字,再弄1個變數記錄該數字後面的位置序號,往後遍歷,直到遇到不一樣的數字,才把那個數字放到該位置序號上來,然後把記錄單獨數字的變數設為這個新數字,記錄位置的變數序號+1,繼續往後遍歷,因為是隨著遍歷過程往前放數字,所以不會影響到後面的數字順序。
Def removeDuplicates(nums):
If len(nums)<=1:
Return len(nums)
Slow = 0
If i range(1, len(nums)):
If nums[i]!=nums[slow]:
Slow += 1
Nums[slow] = nums[i]
Return slow+1
class Solution:
def removeDuplicates(self, nums):
"""
:type nums: List[int]
:rtype: int
"""
'''
思路:
我們弄1個變數記錄上1個單獨的數字,再弄1個變數記錄該數字後面的位置序號,往後遍歷,直到遇到不一樣的數字,才把那個數字放到該位置序號上來,然後把記錄單獨數字的變數設為這個新數字,記錄位置的變數序號+1,繼續往後遍歷,因為是隨著遍歷過程往前放數字,所以不會影響到後面的數字順序。
'''
if len(nums)<=1:
return len(nums)
slow = 0
for i in range(1, len(nums)):
if nums[i]!= nums[slow]:#其中nums[slow]表示上1個數字
slow += 1
nums[slow] = nums[i]
return slow + 1
122. 買賣股票的最佳時機II
給定1個數組,它的第i個元素是1支給定股票第i天的價格。
設定1個演算法來計算你所能獲取的最大利潤,你可以儘可能地完成更多的交易(多次買賣一支股票)。
注意:你不能同時參與多筆交易(你必須在再次購買前出售掉之前的股票)
思路:我們遍歷股價,遇到不斷下降的趨勢,我們就等降到了最低再買,然後等他開始上漲到最高點的時候賣出,以此往復,每次的收益累計就是最大收益了。
精華思路:只要第2天有上漲就買入賣出,做短線。
class Solution:
def maxProfit(self, prices):
"""
:type prices: List[int]
:rtype: int
"""
'''
思路:只要第2天有上漲就買入賣出,做短線
'''
sum = 0
for i in range(len(prices)-1):
if prices[i+1]>prices[i]:
sum += prices[i+1] - prices[i]
return sum
189.旋轉陣列
給定1個數組,將陣列中的元素向右移動k個位置,其中k是非負數。
思路:簡單的一種,用另外1個數組來記錄旋轉後的內容,然後複製回原陣列,當然記錄時是從nums.length-k個元素開始記錄,記錄到末尾後再去從頭記錄到剛才那個元素。
需要注意的是這裡並非返回1個數組,程式會直接讀取原陣列位置的內容來檢查,所以需要把旋轉後的結果1個個複製回去。
還有,給出的k可能會大於陣列長度,這時候就要對原陣列取模,才會得到真正需要旋轉的個數!(這是我沒有考慮到的!)
class Solution:
def rotate(self, nums, k):
"""
:type nums: List[int]
:type k: int
:rtype: void Do not return anything, modify nums in-place instead.
"""
'''
最簡單的思路:
直接遍歷k,將得到的數字插入list的第1個位置,最後只返回前len(nums)的list即可
但是!!!注意,本題需要原地修改nums,即不能return任何陣列,因此我們這裡不能採用上面這種方法
!!我沒考慮到的是:給出的k可能會大於陣列長度,這時候就要對原陣列取模,才會得到真正需要旋轉的個數!
@但是我們發現程式設計實現有問題,因此下面的程式碼,直接根據旋轉陣列之後的特徵,來對
原陣列進行切分,經過3次反轉來達到最終目的
'''
if len(nums)==0 or k==0:
return
def reverse(start, end, s):
while start<end:
s[start], s[end] = s[end], s[start]
start += 1
end -= 1
n = len(nums)-1
k = k%len(nums)#給出的k可能會大於陣列長度,這時候就要對原陣列取模
reverse(0, n-k, nums)
reverse(n-k+1, n, nums)
reverse(0, n, nums)
217.存在重複元素
給定1個init型的陣列,判斷陣列是否包含了重複的數。如果有任何的數值在函式中出現過至少2次,你的陣列就應該返回true,如果每個數值都是單一的,那麼就返回false.
思路:先對陣列中的數字進行排序,排序之後,如果有相同的數值,那一定是相鄰排列的,所以只要遍歷陣列檢查是否有相鄰的2個數值相等就可以了。
總結:原來要把對每個數字進行遍歷陣列判斷是否有相同元素,這樣做太麻煩!——>現在轉換思路,將原問題重新分析,變成“排序+判斷相鄰元素是否相等”的問題,就大大清晰了。
class Solution(object):
def containsDuplicate(self, nums):
"""
:type nums: List[int]
:rtype: bool
"""
nums.sort()#先對陣列排序
#再遍歷一遍陣列,判斷是否有相鄰元素相等
for i in range(0, len(nums) - 1):
if nums[i] == nums[i+1]:
return True
return False
136.只出現一次的數字
給定1個非空的整數陣列,除了某個元素只出現1次以外,其餘每個元素均出現2次。找出那個只出現了1次的元素。
思路:出現過1次的元素只有1個,由於相同的元素只出現2次,相同的元素自己內部異或得到的結果是0…0,陣列中除了相同的元素,只有1個出現過1次的元素,因此我們可將找到這個只出現過1次的元素的問題,化為陣列中的元素連續異或的結果(只出現過1次的元素和0…0異或仍然是自己(這個只出現過1次的元素))
class Solution(object):
def singleNumber(self, nums):
"""
:type nums: List[int]
:rtype: int
"""
'''
由於相同的元素只出現2次,相同的元素自己內部異或得到的結果是0...0,
陣列中除了相同的元素,只有1個出現過1次的元素,因此我們可將找到這個
只出現過1次的元素的問題,化為陣列中的元素連續異或的結果(只出現過1次的元素
和0...0異或仍然是自己(這個只出現過1次的元素))
'''
for i in range(1,len(nums)):
nums[0] ^= nums[i]
return nums[0]
350. 2個數組的交集II
給定2個數組,寫1個方法來計算它們的交集
例如:
給定nums1 = [1,2,2,1], nums2=[2,2], 返回[2,2]
注意:
輸出結果中每個元素出現的次數,應與元素在2個數組中出現的次數一致。
我們可以不考慮輸出結果的順序
思路1:暴力查詢法,遍歷第1個列表的每個元素,並在第2個列表中查詢該元素是否出現,若出現,則將其加入到結果集中,並更新第2個列表(在第2個列表中刪除這個元素),如此往復。
思路2:用字典dict統計第1個列表都出現了哪些數,以及出現的次數,然後順序遍歷第2個列表,發現同時出現的數則加入到結果列表中,同時將第1個列表中相應的出現次數減1。
思路3:將執行速度從143ms減少到44s,可以提高效率——>首先對第2個列表進行排序,然後遍歷第1個列表,利用2分查詢法查詢元素是否出現
總結:在2次比遍歷,且有1個遍歷是查詢元素出現的index時,可以轉化為‘排序+二分查詢’的問題來提高效率!
class Solution(object):
def intersect(self, nums1, nums2):
"""
:type nums1: List[int]
:type nums2: List[int]
:rtype: List[int]
"""
'''
思路1:暴力查詢法
'''
# res = []
# for k in nums1:
# index=-1
# for j in range(0, len(nums2)):
# if nums2[j]==k:#當第1個列表的元素,在第2個列表中出現時,則將該元素添 #加到結果集中
# index = j
# break
# if index!=-1:
# res.append(k)
# del nums2[index]#在第2個列表中刪除這個元素
# return res
'''
思路2:
'''
# res = []
# map = {}
# for i in nums1:
# #用字典統計第1個列表中出現了哪些數,以及出現的次數
# map[i] = map[i] + 1 if i in map else 1
# for j in nums2:
# #遍歷第2個列表,發現同時出現在map中的,且這個出現次數>0的,加入到結果res
# if j in map and map[j]>0:
# res.append(j)
# #每加入1個元素,就對map進行更新
# map[j] -= 1
# return res
'''
思路3:可以提高效率
1.先對第2個列表排序
2.再每次檢查元素是否出現時,用二分搜尋
'''
res = []
nums2.sort()
for k in nums1:
flag, j = self.binarySearch(nums2, k)
if flag:
res.append(k)
del nums2[j]
return res
def binarySearch(self, nums, num):
left = 0
right = len(nums) - 1
while left <= right:
mid = (left+right)/2
if nums[mid] == num:
return True, mid
if nums[mid]<num:#這個數<要查詢的數,left指標向mid+1移動
left = mid+1
else:
right = mid-1
return False,0#這裡是沒有找到要查詢的元素
66. 加1
給定1個非負整陣列成的非空陣列,在該數的基礎上加1,返回1個新的陣列。
最高位數字存放在陣列的首位,陣列中每個元素只儲存1個數字。
你可以假設除了整數0以外,整個整數不會以0開頭。
輸入: [1,2,3]
輸出: [1,2,4]
解釋: 輸入陣列表示數字 123。
思路:該題的關鍵點在於對加法進位的判斷,從個位數開始,如果加1後等於10,那麼要進位,而進位時也要對高位進行判斷是否還要進位,如果不進位就直接返回。
需要注意的是:[9,9]+1變成[1,0,0]時,即digits要增加1位時,需要的步驟是在遍歷完digits以後,仍需要進位的時候,返回[1]+digits
class Solution(object):
def plusOne(self, digits):
"""
:type digits: List[int]
:rtype: List[int]
"""
carry = 1
for i in reversed(range(0, len(digits))):
digit = (digits[i] + carry)%10
#digit<digits[i]則有進位
carry = 1 if digit<digits[i] else 0
digits[i] = digit
if carry == 0:
return digits
if carry ==1:#這個是[9,9]+1變成[1,0,0]時,即digits要增加1位時,需要的步驟
return [1]+digits
return digits
283. 移動零
給定1個數組,編寫1個函式將所有的0移動到陣列的末尾,同時保持非0元素的相對順序。
說明:必須在原陣列上操作,不能拷貝額外的陣列;儘量減少操作次數
思路1:從陣列的第1個開始,當發現‘0’以後,立刻在它後面找到第1個不為0的數字,然後交換這2個數字的位置,其餘的數字都不用動。同時,我們檢查當前後面的數字是否都為‘0’,如果都為‘0’,就直接return
思路2:(最有效率!)將所有不為0的數字按照順序移到最前面,定義2個指標i和j,其中i是當前正在判斷的數字,j為所有不為0的的陣列的後置座標(即第1個0的座標,初始設為0)。
class Solution(object):
def moveZeroes(self, nums):
"""
:type nums: List[int]
:rtype: void Do not return anything, modify nums in-place instead.
"""
'''
思路是:將所有不為0的數字按照順序移到前面
'''
i=j=0
for i in range(len(nums)):
if nums[i]!=0:
nums[j],nums[i] = nums[i], nums[j]
j+=1
1. 兩數之和
給定1個整數陣列和1個目標值,找出陣列中和為目標值的2個數。
你可以假設每個輸入只對應1種答案,且同樣的元素不能被重複利用。
示例:
給定 nums = [2, 7, 11, 15], target = 9
因為 nums[0] + nums[1] = 2 + 7 = 9
所以返回 [0, 1]
思路:2個關鍵點,1是記錄出現過的數字,由於可能有負數,因此已經無法縮小要記錄的數字的範圍了。2是要記錄數字所在的位置。
我們遍歷陣列,每次出現的數字以及其位置,數值是key,位置是值,同時判斷之前有沒有記錄過正好與當前數字相加等於目的數的數字,有就return
class Solution(object):
def twoSum(self, nums, target):
“””
:type nums: List[int]
:type target: int
:rtype: List[int]
“””
”’
思路:
”’
d = {}
for i,num in enumerate(nums):
#最開始d是空dict的時候不用怕!因為相加的2個元素是互補的,因此在即使在前面沒有找到,在後面也可以找到
if target - num in d:
return [d[target-num], i]
d[num] = i
class Solution(object):
def twoSum(self, nums, target):
"""
:type nums: List[int]
:type target: int
:rtype: List[int]
"""
'''
思路:
'''
d = {}
for i,num in enumerate(nums):
#最開始d是空dict的時候不用怕!因為相加的2個元素是互補的,因此在即使在前面沒有找到,在後面也可以找到
if target - num in d:
return [d[target-num], i]
d[num] = i
36.有效的數獨
判斷1個9*9的數獨是否有效,只需要根據以下規則,驗證已經填入的數字是否有效即可。
(1) 數字1-9在每1行只能出現1次。
(2) 數字在每一列只能出現1次。
(3) 數字1-9在每1個以粗實線分隔的3*3宮內只能出現1次
上圖是1個部分填充的有效的數獨,可以表示為以下形式,其中空白格用‘.’表示。
示例 2:
輸入:
[
[“8”,”3”,”.”,”.”,”7”,”.”,”.”,”.”,”.”],
[“6”,”.”,”.”,”1”,”9”,”5”,”.”,”.”,”.”],
[“.”,”9”,”8”,”.”,”.”,”.”,”.”,”6”,”.”],
[“8”,”.”,”.”,”.”,”6”,”.”,”.”,”.”,”3”],
[“4”,”.”,”.”,”8”,”.”,”3”,”.”,”.”,”1”],
[“7”,”.”,”.”,”.”,”2”,”.”,”.”,”.”,”6”],
[“.”,”6”,”.”,”.”,”.”,”.”,”2”,”8”,”.”],
[“.”,”.”,”.”,”4”,”1”,”9”,”.”,”.”,”5”],
[“.”,”.”,”.”,”.”,”8”,”.”,”.”,”7”,”9”]
]
輸出: false
解釋: 除了第一行的第一個數字從 5 改為 8 以外,空格內其他數字均與 示例1 相同。
但由於位於左上角的 3x3 宮內有兩個 8 存在, 因此這個數獨是無效的。
說明:
(1)一個有效的數獨(部分已被填充)不一定是可解的。
(2)只需要根據以上規則,驗證已經填入的數字是否有效即可。
(3)給定數獨序列只包含數字 1-9 和字元 ‘.’ 。
(4)給定數獨永遠是 9x9 形式的。
思路1:(暴力查詢)按照規則,數獨只1-9在行、列、3*3宮格中都只出現1次。因此我們可以分別檢驗3次來判斷給出的數獨是否有效。
class Solution:
def isValidSudoku(self, board):
"""
:type board: List[List[str]]
:rtype: bool
"""
for i in range(9):
if not self.isValidNine(board[i]):#檢測行是否有重複的數,第i行board[i]
return False
col = [c[i] for c in board]#生成列第i列col
if not self.isValidNine(col):#檢測列
return False
for i in [0,3,6]:#檢測3*3小方格
for j in [0,3,6]:
block = [board[s][t] for s in [i,i+1,i+2] for t in [j,j+1,j+2]]
if not self.isValidNine(block):
return False
return True
def isValidNine(self, row):
map={}
for c in row:
if c != '.':
if c in map:
return False
else:
map[c] = True
return True
48. 旋轉影象
給定1個n*n的二維矩陣表示1個影象,將影象順時針旋轉90度。
說明:你必須在原地旋轉影象,這意味著你需要直接修改輸入的二維矩陣。請不要使用另外1個矩陣來旋轉影象。
示例 1:
給定 matrix =
[
[1,2,3],
[4,5,6],
[7,8,9]
],
原地旋轉輸入矩陣,使其變為:
[
[7,4,1],
[8,5,2],
[9,6,3]
]
思路:觀察input和output的矩陣,可以將旋轉90度拆分為2步:第1步,沿對角線調換2遍的元素,第2步,沿著豎直方向的中線,調換左右兩邊的元素。
1 2 3 1 4 7 7 4 1
4 5 6 2 5 8 8 5 2
7 8 9 3 6 9 9 6 3
第一步,根據紅色的對角線,找對應位置,互換兩個數字的值。
第二步,對每一行數字,根據中線左右翻轉
class Solution:
def rotate(self, matrix):
"""
:type matrix: List[List[int]]
:rtype: void Do not return anything, modify matrix in-place instead.
"""
if len(matrix)==0:
return
h = len(matrix)
w = len(matrix[0])
for i in range(h):
#需要注意的是j從i+1開始遍歷!!
for j in range(i+1,w):
matrix[j][i],matrix[i][j] = matrix[i][j],matrix[j][i]
for i in range(h):
for j in range(w//2):
matrix[i][w-1-j],matrix[i][j] = matrix[i][j],matrix[i][w-1-j]
return
專題二:字串:
344.反轉字串
請編寫1個函式,其功能是將輸入的字串反轉過來。
示例:
輸入:s = “hello”
返回:”olleh”
思路1:使用原生方法實現(by Danny)
思路2:利用python的字串操作(return s[::-1])
思路3:利用雙指標,依次交換前面和後面的字元直至中間字元,完成反轉。
class Solution:
def reverseString(self, s):
"""
:type s: str
:rtype: str
"""
'''
使用原生方法,很簡單就能實現
'''
# s_list = list(s)
# if len(s_list)<=1:
# return s
# s_list.reverse()
# for index,t in enumerate(s_list):
# if index==0:
# res = t
# continue
# res+=t
# return res
'''
利用python的字串操作
'''
# return s[::-1]
'''
思路3:
利用雙指標,依次交換前面和後面的字元直至中間字元,完成反轉
'''
s = list(s)
for i in range(len(s)//2):
s[len(s)-1-i], s[i] = s[i], s[len(s)-1-i]
return ''.join(s)
7.反轉整數
給定1個32位有符號整數,將整數中的數字進行反轉。
示例 2:
輸入: -123
輸出: -321
注意:
假設我們的環境只能儲存 32 位有符號整數,其數值範圍是 [−231, 231 − 1]。根據這個假設,如果反轉後的整數溢位,則返回 0。
思路:這道題的關鍵點其實是對超大數溢位的判斷,溢位需要返回0。
關注幾個邊界:1.原整數以0結尾,該如何處理?比如10或100,反轉後都為1;2.原整數反轉後溢位怎麼辦?比如比如x=1000000003,反轉溢位,那麼規定溢位的結果都返回0。
具體方法1:迴圈通過對10取模得到尾部數字,一步步乘以10構造新的翻轉後的整數即可。然而要注意首先判斷原數字的正負,最後還要判斷結果是否溢位。
具體方法2:利用字串的反轉操作來實現對整數的反轉,反轉後的字串要重新轉換為整數,同時需要注意正負和溢位2種情況。
class Solution:
def reverse(self, x):
"""
:type x: int
:rtype: int
"""
'''
思路1
'''
# flag = 1 if x>=0 else -1#判斷原數字的正負號
# new_x, x = 0, abs(x)
# while x:
# new_x = 10*new_x+x%10 #x%10是模
# x = x//10
# new_x = flag*new_x # 還原數字的正負號
# return new_x if new_x < 2147483648 and new_x>=-2147483648 else 0
'''
思路2
'''
x = int(str(x)[::-1]) if x>0 else -int(str(-x)[::-1])
return x if x<2147483648 and x>=-2147483648 else 0
387.字串中的第1個唯一字元
給定1個字串,找到它的第1個不重複的字元,並返回它的索引。如果不存在,則返回-1.
案例:
s = “leetcode”
返回 0.
s = “loveleetcode”,
返回 2.
注意事項:可以假定該字串只包含小寫字母
思路1:建立1個長度為26的陣列,存放字串的每個字元的出現次數,然後遍歷找到第1個為次數為1的字元的index。
思路2:用字串內建的count方法,用時更短。只需要1個迴圈。
class Solution:
def firstUniqChar(self, s):
"""
:type s: str
:rtype: int
"""
'''
不能用dict,因為放入dict裡以後,不按照放入的順序排列
'''
# letters = [0]*26
# for c in s:
# ci = ord(c) - ord('a')#減去ord('a')是為了使ci在0-26範圍內
# letters[ci]+=1
# for i in range(0, len(s)):
# ci = ord(s[i]) - ord('a')
# if letters[ci]==1:
# return i
# return -1
'''
用字串內建的count方法,用時更短!
'''
have_done = []
for i in range(0, len(s)):
if s[i] not in have_done:
if s.count(s[i])==1:
return i
else:
have_done.append(s[i])
else:
continue
return -1
242.有效的字母異位詞
給定2個字串s和t,編寫1個函式來判斷t是否是s的1個字母異位詞。
示例 1:
輸入: s = “anagram”, t = “nagaram”
輸出: true
示例 2:
輸入: s = “rat”, t = “car”
輸出: false
說明:你可以假設字串只包含小寫字母
進階:如果輸入字串包含unicode字元怎麼辦?你能否調整你的解法來應對這種情況?
思路1:用2個int陣列,分別記錄2個字串中各個字母出現的次數,然後分別遍歷2個數組,記錄其各個字母出現的次數,最後比較2個int陣列是否完全一致就可以了。
思路2:更有效率的方法!其改進是,只用1個int陣列,先遍歷1個字母串,記錄下每個字母出現的次數,然後遍歷另1個字串,出現某個字母就對之前的那個int陣列對應的位置減1,最後遍歷int陣列,判斷是否所有元素都為0,不是的話返回False,是的話返回True.
class Solution:
def isAnagram(self, s, t):
"""
:type s: str
:type t: str
:rtype: bool
"""
letters = [0]*26
for c in s:
ci = ord(c) - ord('a')#減去ord('a')是為了使ci在0-26範圍內
letters[ci]+=1
for c in t:
ci = ord(c) - ord('a')
letters[ci]-=1
for c in letters:
if c!=0:
return False
return True
125.驗證迴文字串
給定1個字串,驗證它是否是迴文串,只考慮字母和數字字元,可以忽略字母的大小寫。
說明:本題中,我們將空字串定義為有效的迴文串。
示例 1:
輸入: “A man, a plan, a canal: Panama”
輸出: true
示例 2:
輸入: “race a car”
輸出: false
思路:迴文的定義可以從2個例子中看出:是該字串是左右對稱的!因為在這個例子中是忽略字母的大小寫的,因此我們可以將所有字母都轉換為小寫(用.lower()函式)的來判斷!
這裡我們可以用2個指標,標記頭尾,來遍歷字串。
PS:需要注意的是,我們這裡要忽略字串中空格和其他標點符號!因此,我們需要判斷頭尾拿來比較的元素是不是數字或者大小寫字母(這裡我們用內建函式.isalnum()來判斷!)
Python isalnum() 方法檢測字串是否由字母和數字組成,如果 string 至少有一個字元並且所有字元都是字母或數字則返回 True,否則返回 False。
class Solution:
def isPalindrome(self, s):
"""
:type s: str
:rtype: bool
"""
start,end=0, len(s)-1
while start<end:
if not s[start].isalnum():#如果是空格和其他標點符號,則忽略
start+=1
continue
if not s[end].isalnum():
end-=1
continue
if s[start].lower()!=s[end].lower():
return False
start +=1
end -= 1
return True
8.字串轉整數(atoi)
實現atoi,將字串轉為整數。
在找到第1個非空字元之前,需要移除掉字串中的空格字元。
如果第1個非空字元是正號或負號,選取該符號,並將其與後面儘可能多的連續的數字組合起來,這部分字元為整數的值。如果第1個非空字元是數字,則直接將其與之後連續的數字字元組合起來,形成整數。
字串可以在形成整數的字元後面,包含多餘的字元,這些字元可以被忽略,它們對於函式沒有影響。
當字串中的第1個非空字元序列不是個有效的整數,或字串為空,或字串僅僅包含空白字元時,則不進行轉換。
若函式不能執行有效的轉換,返回0.
示例 1:
輸入: “42”
輸出: 42
示例 2:
輸入: ” -42”
輸出: -42
解釋: 第一個非空白字元為 ‘-‘, 它是一個負號。
我們儘可能將負號與後面所有連續出現的數字組合起來,最後得到 -42 。
示例 3:
輸入: “4193 with words”
輸出: 4193
解釋: 轉換截止於數字 ‘3’ ,因為它的下一個字元不為數字。
示例 4:
輸入: “words and 987”
輸出: 0
解釋: 第一個非空字元是 ‘w’, 但它不是數字或正、負號。
因此無法執行有效的轉換。
示例 5:
輸入: “-91283472332”
輸出: -2147483648
解釋: 數字 “-91283472332” 超過 32 位有符號整數範圍。
因此返回 INT_MIN (−231) 。
思路:利用strip函式(Python strip() 方法用於移除字串頭尾指定的字元(預設為空格或換行符)或字元序列。注意:該方法只能刪除開頭或是結尾的字元,不能刪除中間部分的字元。)並且利用isdigit()函式判斷字元是否是數字。
class Solution:
def myAtoi(self, str):
"""
:type str: str
:rtype: int
"""
s = str.strip()#去掉頭尾的空白字元
sign = 1
#空字串,不能轉換,直接返回0
if not s:
return 0
'''
考慮幾種情況:
1.第1個非空字元是正號或負號
2.第1個非空字元是數字
(數字中間夾了其餘非數字字元的話就不考慮後面的內容了)
3.第1個非空字元不是正負號或數字,直接返回0
'''
if s[0] in ['+','-']:
if s[0]=='-':
sign = -1
s = s[1:]
res = 0
for c in s:
if c.isdigit():
res = res*10+int(c)
else:
#代表數字中間夾了其餘非數字字元的話就不考慮後面的內容了
break
res *= sign
#判斷溢位
if res>2147483647:
return 2147483647
if res<-2147483648:
return -2147483648
return res
28.實現strStr()
給定1個haystack字串和1個needle字串,在haystack字串中找出的第1個位置(從0開始)。如果不存在,則返回-1
示例 1:
輸入: haystack = “hello”, needle = “ll”
輸出: 2
示例 2:
輸入: haystack = “aaaaa”, needle = “bba”
輸出: -1
說明:
當 needle 是空字串時,我們應當返回什麼值呢?這是一個在面試中很好的問題。
對於本題而言,當 needle 是空字串時我們應當返回 0 。這與C語言的 strstr() 以及 Java的 indexOf() 定義相符。
思路1:掃描haystack,當遇到與needle首字元相同的位置時,檢查haystack從該位置開始的與needle長度相同的塊,與needle是否相同。
思路2:
思路3:這是1個模式匹配的問題,因此我們考慮KMP演算法。該演算法對於任何模式和目標序列,都可以線上性時間內完成匹配查詢(O(n+m)),而不會發生退化。
class Solution:
def strStr(self, haystack, needle):
"""
:type haystack: str
:type needle: str
:rtype: int
"""
'''
使用KMP演算法
'''
s = haystack
t = needle
if len(needle)==0:
return 0
slen = len(s)
tlen = len(t)
if slen>=tlen:
i=0
j=0
next_list = [-2 for i in range(tlen)]
self.getNext(t, next_list)
while i < slen:
if j==-1 or s[i]==t[j]:
i+=1
j+=1
else:
j = next_list[j]
if j==tlen:
return i-tlen
return -1
def getNext(self,t, next_list):
next_list[0]=-1
j = 0
k = -1
while j< len(t)-1:
if k==-1 or t[j] == t[k]:
j+=1
k+=1
next_list[j]=k
else:
k = next_list[k]
38.報數
報數序列是指一個整數序列,按照其中的整數的順序進行報數,得到下一個數。其前五項如下:
1. 1
2. 11
3. 21
4. 1211
5. 111221
1 被讀作 “one 1” (“一個一”) , 即 11。
11 被讀作 “two 1s” (“兩個一”), 即 21。
21 被讀作 “one 2”, “one 1” (”一個二” , “一個一”) , 即 1211。
給定一個正整數 n ,輸出報數序列的第 n 項。
注意:整數順序將表示為一個字串。
示例 1:
輸入: 1
輸出: “1”
示例 2:
輸入: 4
輸出: “1211”
思路1:完全按照規則寫,用到3個迴圈,最外層是生成第幾個序列,中間層用於遍歷1個序列,最內層找出連續相同的幾個數字
class Solution:
def countAndSay(self, n):
"""
:type n: int
:rtype: str
"""
# res = '1'
# for i in range(n-1):
# new_res = ''
# j = 0
# while j<len(res):
# count = 1#統計j以後有幾個元素==res[j]
# while j<len(res)-1 and res[j]==res[j+1]:
# j = j+1
# count = count+1
# new_res = new_res + str(count) + res[j]
# j = j+1
# res = new_res
# return res
'''
思路2:中間層迴圈和最內層迴圈不分開寫,用1個per變數存放上1個字元
'''
res = '1'
for i in range(n-1):
new_res=''
pre=res[0]
count=0
for j in range(len(res)):
if res[j]==pre:
count+=1
else:
new_res = new_res+str(count)+pre
pre=res[j]
count=1
res = new_res+str(count)+pre#這裡的+str(count)+pre是將最後1個字母的報數加入
return res
14.最長公共字首
寫1個函式來尋找1個數組的字串中最長的相同字首。
如果不存在公共字首,返回空字串 “”。
示例 1:
輸入: [“flower”,”flow”,”flight”]
輸出: “fl”
示例 2:
輸入: [“dog”,”racecar”,”car”]
輸出: “”
解釋: 輸入不存在公共字首。
說明: 所有輸入只包含小寫字母 a-z 。
思路1:暴力解決,用多個指標來解決(需要考慮很多特殊情況)
思路2:先用整個第1個字串當做字首去判斷每個字串是否擁有該字首,沒有就將這個字首末尾字元去掉,再繼續比較,直到當前判斷的字串有這個字首了,才去判斷下1個字串有沒有,執行相同的操作。當任何時候字首長度減少到0了,也可以直接返回了。(好處是不需要考慮特徵情況)
想到思路2的關鍵點是:建立假設:假設整個第1個字串為字首!
因此很多提高效率的方法可以使用假設法!!!
具體實現:其中可以使用函式Python index() 方法檢測字串中是否包含子字串 str ,如果指定 beg(開始) 和 end(結束) 範圍,則檢查是否包含在指定範圍內,該方法與 python find()方法一樣,只不過如果str不在 string中會報一個異常。
str.index(str, beg=0, end=len(string))
str – 指定檢索的字串
beg – 開始索引,預設為0。
end – 結束索引,預設為字串的長度
其實這個index()方法是用KMP實現的,當我們自己實現的時候可以用KMP演算法
class Solution:
def longestCommonPrefix(self, strs):
"""
:type strs: List[str]
:rtype: str
"""
'''
簡化思路的關鍵是:建立合理的假設!比如這題,我們可以建立假設:假設整個第1個字串為字首。然後去判斷每個字串是否擁有該字首。沒有的話就將該字首-末尾字元,在用這個更新過的字首去繼續判斷。
PS:但是這個思路的程式碼跑起來有問題,主要是使用內建函式index那個地方,換成自己實現的KMP應該就好了,但是我沒有做,還是直接用暴力解了,看思路2
'''
# if len(strs)==0:
# return ''
# pre = strs[0]
# for i in range(len(strs)):
# while strs[i].index(pre)!=0:#pre字串需要出現在strs[i]的第1個位置,如果不是則pre=pre[:-1]
# pre = pre[:-1]
# if len(pre)==0:return ''
# return pre
'''
思路2:暴力解法
'''
if len(strs) == 0:
return ''
i = 0
j = 0
end = 0
while j<len(strs) and i<len(strs[j]):
#j代表第j個字串,i代表字串中的第i個字元
if j==0:
#char賦值每次正在判斷的單個字首字元
char = strs[j][i]
else:
if strs[j][i]!=char:
#判斷每個字串的第i個字元是否和char相等,一旦不符則跳出
break
if j==len(strs)-1:
#如何1個字首字元判斷完了,則判斷下1個字元是不是字首字元
i+=1
j=0
end +=1
else:
j+=1
return strs[j][:end]
專題三:連結串列:
總結:常用的方法有:快慢指標法。
237.刪除連結串列中的節點
請編寫一個函式,使其可以刪除某個連結串列中給定的(非末尾)節點,你將只被給定要求被刪除的節點。
現有一個連結串列 – head = [4,5,1,9],它可以表示為:
4 -> 5 -> 1 -> 9
示例 1:
輸入: head = [4,5,1,9], node = 5
輸出: [4,1,9]
解釋: 給定你連結串列中值為 5 的第二個節點,那麼在呼叫了你的函式之後,該連結串列應變為 4 -> 1 -> 9.
示例 2:
輸入: head = [4,5,1,9], node = 1
輸出: [4,5,9]
解釋: 給定你連結串列中值為 1 的第三個節點,那麼在呼叫了你的函式之後,該連結串列應變為 4 -> 5 -> 9.
說明:(1)連結串列至少包含2個節點
(2)連結串列中所有節點的值都是唯一的
(3)給定的節點為非末尾節點並且一定是連結串列中的1個有效節點。
(4)不要從你的函式中返回任何結果。
思路:一般我們刪除1個連結串列節點,直接將其上1個節點的next指向下一個節點就可以了。
但是!這裡只給了該節點本身,即我們只能獲取到該節點本身以及其下一個節點。因此我們將當前節點的下一個節點的值變成當前節點的值,將當前節點的下一個節點的下一節點變成當前節點的next.
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, x):
# self.val = x
# self.next = None
class Solution:
def deleteNode(self, node):
"""
:type node: ListNode
:rtype: void Do not return anything, modify node in-place instead.
"""
node.val = node.next.val
node.next = node.next.next
19. 刪除連結串列的倒數第N個節點。
給定1個連結串列,刪除連結串列的倒數第n個節點,並且返回連結串列的頭節點。
示例:
給定一個連結串列: 1->2->3->4->5, 和 n = 2.
當刪除了倒數第二個節點後,連結串列變為 1->2->3->5.
說明:
給定的 n 保證是有效的。
進階:
你能嘗試使用一趟掃描實現嗎?
思路:(使用了2個指標來簡化問題)設定了快慢2個標記,初始都在頭節點,快的先往後遍歷,遍歷到與頭節點相差為n的時候停止,然後快的和慢的一起往後走,直到快的走到了連結串列尾節點為止,這時候快慢2個節點之間相差的節點數正好是n,也就是說慢的所在的下1個節點正好是要刪除的節點,直接跳過去就可以了,一遍遍歷完成!
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, x):
# self.val = x
# self.next = None
class Solution:
def removeNthFromEnd(self, head, n):
相關推薦
leetcode探索專題中的初級演算法練習題(python程式碼+解題思路)
本文記錄leetcode探索專題中的初級演算法練習題,附python實現程式碼&解題思路,做題過程不免查閱網路資料,侵刪~如有錯誤,歡迎指正交流!
目錄
專題一:陣列:
26.從排序陣列中刪除重複項
給定1個排序陣列,你需要在原地刪
PythonNLP學習進階:第二章練習題(Python自然語言處理)
python自然語言處理.2014年7月第一版課後習題練習
1.
>>> phrase=["Valentine's"]
>>> phrase=["lonely"]+phrase+["day"]
>>> phrase
[
Shape屬性之圓角(實現程式碼及思路)
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<!--設定背景色-->
<soli
Leetcode初級演算法 打家劫舍(動態規劃)(Python實現)
問題描述:
演算法思想:
該問題的內在邏輯結構依然是動態規劃裡的經典結構。最關鍵的是推出狀態轉移方程,當前規模的對應解法由更低規模的解法,彷彿拾級而上,站在前人的肩膀上不斷攀登。
實際操作起來,比較實用的方法如下:固定一個比較小的規模n, 進行思維實驗。
例子:
LeetCode初級演算法問題(字串)
反轉字串class Solution(object):
def reverseString(self, s):
"""
:type s: str
:rtype: str
"""
retur
LeetCode——反轉字串中的母音字母(JavaScript)
編寫一個函式,以字串作為輸入,反轉該字串中的母音字母。
示例 1:
輸入: "hello"
輸出: "holle"
示例 2:
輸入: "leetcode"
輸出: "leotcede"
說明: 母音字母不包含字母"y"。
思路:
典型的雙指標——對撞指標解法。設定
leetcode-94-二叉樹的中序遍歷(binary tree inorder traversal)-java
題目及測試
package pid094;
import java.util.List;
/*中序遍歷二叉樹
給定一個二叉樹,返回它的中序 遍歷。
示例:
輸入: [1,null,2,3]
1
\
2
/
3
輸出: [1,3,2]
進階:
LeetCode 442. 陣列中重複的資料(C、C++、python)
給定一個整數陣列 a,其中1 ≤ a[i] ≤ n (n為陣列長度), 其中有些元素出現兩次而其他元素出現一次。
找到所有出現兩次的元素。
你可以不用到任何額外空間並在O(n)時間複雜度內解決這個問題嗎?
示例:
輸入:
[4,3,2,7,8,2,3,1]
輸出
leecode中初級演算法中陣列加一
js解法及思路
/**
* @param {number[]} digits
* @return {number[]}
*/
/**
注意點
1.最後一位是否為9,為9的話,要進位,賦0下一位加1
2.如果首位為0,加一,首位為9整個陣列必是返回【10000...】
整個
記錄一個演算法題(java程式碼):統計正整數n的二進位制寫法中有多少個1
package ludims.main;
import java.util.Scanner;
public class myMain {
public static void main(String[] args) {
System.out.pri
LeetCode 434.字串中的單詞數(Number of Segments in a String)C C++
統計字串中的單詞個數,這裡的單詞指的是連續的不是空格的字元。
請注意,你可以假定字串裡不包括任何不可列印的字元。
示例:
輸入: "Hello, my name is John"
輸出:
【LeetCode & 劍指offer刷題】回溯法與暴力列舉法題2:12 矩陣中的字串查詢(79. Word Search 系列)
【LeetCode & 劍指offer 刷題筆記】目錄(持續更新中...)
12 矩陣中的字串查詢(79. Word Search 系列)
Word Search
Given a 2D board and a word, find if
推薦系統實踐----基於使用者的協同過濾演算法(python程式碼實現書中案例)
本文參考項亮的《推薦系統實踐》中基於使用者的協同過濾演算法內容。因其中程式碼實現部分只有片段,又因本人初學,對python還不是很精通,難免頭大。故自己實現了其中的程式碼,將整個過程走了一遍。
1. 過程簡述
a. 首先我們因該先找到和目標使用者興趣相似的使用者集合。簡單來
分散式系統中的演算法設計(一) -- 一致性 Hash
Hash 大家都知道,把某個要儲存的內容的索引 key 通過某個規則計算一下,算出來一個值,這個值往往範圍比原來小,且概率意義上不會衝突。
由於 Hash 計算複雜度往往比查詢要快,被大量應用到各種大規模的系統中,特別是分散式系統。具體實踐中有幾個典型的問題。
問題來
探索Android中的Parcel機制(上)
一.先從Serialize說起
我們都知道JAVA中的Serialize機制,譯成序列化、序列化……,其作用是能將資料物件存入位元組流當中,在需要時重新生成物件。主要應用是利用外部儲存裝置儲存物件狀態,
遠程調試部署在Tomcat中的應用服務(2種配置方式)
tab jdk1 exe java ee center 右鍵 eclipse 找到 platform 遠程調試部署在Tomcat中的應用服務(tomcat 遠程debug 配置文件)
方法一(編輯catalina.bat)
1. D:\iVMS_Platform\bin\a
JAVA中反射機制六(java.lang.reflect包)
instance 檢查 item 類繼承 final win 基類 cte member 一、簡介
java.lang.reflect包提供了用於獲取類和對象的反射信息的類和接口。反射API允許對程序訪問有關加載類的字段,方法和構造函數的信息進行編程訪問。它允許在安全限制
中位數的性質 (數學真是有趣啊) 太強了
得出 數學 所有 等於 給定 個數 最小 div 中位數 1、中位數的性質
給定一個數列,中位數有這樣的性質 :所有數與中位數的絕對差之和最小
2、中位數性質的簡單證明
首先,給定一個從小到大的數列x1,x2,……
css 3 中的動畫呈現(11月18日)
css 3動畫一、2D/3D的轉換:transform向元素應用 2D 或 3D 轉換。(1)平移屬性:transform:translate(x,y)其中只寫一項的值為左右平移的值。(數值的正負性:左負右正,上負下正)transform:translateX()僅限左右移動。transform:transl
ES6中的Map集合(與java裏類似)
遍歷 也有 實現 數組 _id getname 私有 而且 click Set類型可以用來處理列表中的值,但是不適用於處理鍵值對這樣的信息結構。ES6也添加了Map集合來解決類似的問題
一、Map集合
JS的對象(Object),本質上是鍵值對的集合(Hash結構)