1. 程式人生 > >leetcode探索專題中的初級演算法練習題(python程式碼+解題思路)

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 StringC 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結構)