劍指offer_Python解題(三)

31、從1到n的整數中1出現的個數

比如,1-13中,1出現6次,分別是1,10,11,12,13。

31.1 思路

  • 除以10 遍歷

1- 一個數和10求餘等於1則記錄一次
2- 再將這個數整除10,再判斷一條件

31.2 解題

def NumberOf1Between1AndN_Solution(n):
    res = 0
    for i in range(1, n+1):
        while i != 0:
            if i % 10 == 1:
                res += 1
            i //= 10
    return res

"""
>>> NumberOf1Between1AndN_Solution(13)
6
"""

32、把數組排成最小的數

輸入一個正整數數組,把數組裏所有數字拼接起來排成一個數,打印能拼接出的所有數字中最小的一個。例如輸入數組{3,32,321},則打印出這三個數字能排成的最小數字爲321323

32.1 思路

  • 遍歷 對數組內的數字兩兩比較,尋找str1str2,和str2str1兩種組合中較小的一個。

1- 先找到最小的前面兩個組合
2- 再去找後續最小的兩個組合
3- 每次調換順序,最後合併

例如:
[123, 1, 9]
1-
1-1 比較 1231 & 1123 -->> 1123 -> [1, 123, 9]
1-2 比較 19 & 91 -->> 19 -> [1, 123, 9]
2- 已經確認第一位
2-1 比較 1239 & 9123 -->> 1239 -> [1, 123, 9]
-------- >>> [1, 123, 9] --> 11239

32.2 解題

def PrintMinNumber(numbers):
    if not numbers:
        return ''
    len_num = len(numbers)
    # 1- 轉文本
    numbers = [str(num) for num in numbers]
    # 
    for i in range(len_num-1): # 從頭遍歷
        for j in range(i+1, len_num): # 從+1開始
            # 依次次比較組合,然後調換位置,一一比較
            if numbers[j] + numbers[i] < numbers[i] + numbers[j]:
                numbers[i],numbers[j] = numbers[j],numbers[i]
    return ''.join(numbers)

"""
>>> PrintMinNumber([123, 1, 9] )
'11239'
"""

33、醜數

把只包含質因子2、3和5的數稱作醜數。例如6、8都是醜數,但14不是,因爲它包含質因子7。習慣上我們把1當做是第一個醜數。求按從小到大的順序的第N個醜數。

33.1 思路

  • 逐步生成醜數

1- 每次生成3個醜數
2- 最小的那個就是需要的第n個醜數
3- 計數器(loop_n)作爲循環限制

例如:
第6個醜數
1- loop_n = 5, res = 1
1-1 增加(res)1 * 醜數因子[2, 3, 5] -> ugly_set = {2,3,5}
  取最小 -> res = 2
  去最小 -> {3, 5}
  loop_n = 4

1-2 增加(res)2 * 醜數因子[4, 6, 10] -> ugly_set = {3,5, 4, 6, 10}
  取最小 -> res = 3
  去最小 -> {5, 4, 6, 10}
  loop_n = 3

1-3 增加(res)3 * 醜數因子[6, 9, 15] -> ugly_set = {5, 4, 6, 10, 9, 15}
  取最小 -> res = 4
  去最小 -> {5, 6, 10, 9, 15}
  loop_n = 2

1-4 增加(res)4 * 醜數因子[8, 12, 20] -> ugly_set = {5, 6, 10, 9, 15, 8, 12, 20}
  取最小 -> res = 5
  去最小 -> {6, 10, 9, 15, 8, 12, 20}
  loop_n = 1

1-5 增加(res)5 * 醜數因子[10, 15, 25] -> ugly_set = {6, 10, 9, 15, 8, 12, 25}
  取最小 -> res = 6
  去最小 -> {10, 9, 15, 8, 12, 25}
  loop_n = 0 -> 停止循環

—>>> res = 6

33.2 解題

def GetUglyNumber_Solution(n):
    if n == 0:
        return 0
    loop_n = n - 1
    res = 1
    ugly_set = set()
    while loop_n:
        loop_n -= 1
        ugly_set.add(2 * res)
        ugly_set.add(3 * res)
        ugly_set.add(5 * res)
        res = min(ugly_set)
        ugly_set.remove(res)

    return res

"""
>>> GetUglyNumber_Solution(6)
6
"""

34、第一個只出現一次的字符

在一個字符串(0<=字符串長度<=10000,全部由字母組成)中找到第一個只出現一次的字符,並返回它的位置, 如果沒有則返回 -1(需要區分大小寫)。

34.1 思路

  • 思路:創建哈希表,下標爲ACII值,值爲出現次數。

34.2 解題

def FirstNotRepeatingChar(s):
    ls = [0]*256 # ASCII值
    for i in s:
        ls[ord(i)] += 1
    for j in s:
        if ls[ord(j)] == 1:
            return s.index(j)
            break
    return -1

35、數組中的逆序對

在數組中的兩個數字,如果前面一個數字大於後面的數字,則這兩個數字組成一個逆序對。輸入一個數組,求出這個數組中的逆序對的總數P。並將P對1000000007取模的結果輸出。 即輸出P%1000000007

35.1 思路

  • 思路:暴力雙指針遍歷

35.2 解題

def InversePairs(lst):
    n = len(lst)
    cnt = 0
    for i in range(n-1):
        for j in range(i + 1, n):
            if lst[i] > lst[j]:
                cnt += 1
    return cnt%1000000007

"""
>>> InversePairs([3, 5, 6 ,1, 2, 3])
8
"""

37、統計一個數字在排序數組中的出現的次數

考慮數組爲空的情況,直接返回0

37.1 思路

  • 思路:暴力雙指針遍歷

37.2 解題

def GetNumberOfK(lst, k):
    loop_times = 0
    if lst == []:
        return 0
    if (lst[0] > k) or (lst[-1] < k):
        return 0

    n = len(lst)
    i, j = 0, n-1
    while i < j and  lst[i] != lst[j]:
        loop_times += 1
        if lst[i] != k:
            i += 1
        if lst[j] != k:
            j -= 1

    print(f'loop times: {loop_times}')
    return j - i + 1

"""
>>> GetNumberOfK([1,1,2,3,4,5,6,6,7], 1)
2
"""

37.3 優化解題

  • 思路: 已經排好序,

1- 二分定位
2- 小範圍雙指針遍歷

def GetNumberOfK_fst(lst, k):
    if lst == []:
        return 0
    if (lst[0] > k) or (lst[-1] < k):
        return 0
    n = len(lst)
    i, j = 0, n-1
    loop_times = 0
    print(f'now the range of lst: [{i} , {j}]' )
    # 1- 縮小區間
    while i < j:
        loop_times += 1
        tmp_i , tmp_j = i, j
        if lst[(j - i)//2] < k :
            i = (j - i)//2
        elif lst[(j - i)//2] > k :
            j = (j - i)//2
        # 當中間位置就是需要查找的值的時候退出
        if tmp_i == i and tmp_j == j:
            # 當中間值剛剛好是最後個或第一個K時
            if lst[(j - i)//2] == k and  lst[(j - i)//2 + 1] > k:
                    j = (j - i)//2
            if lst[(j - i)//2] == k and  lst[(j - i)//2 - 1] < k:
                    i = (j - i)//2    
            break

    print(f'now the range of lst: [{i} , {j}]' )
    # 2- 小範圍內遍歷
    while i < j and  lst[i] != lst[j]:
        loop_times += 1
        if lst[i] != k:
            i += 1
        if lst[j] != k:
            j -= 1
    print(f'loop times: {loop_times}')
    return j - i +1
    
"""
>>> lst = [1]*9 + [2]*10 + [3]*10000
>>> GetNumberOfK_fst(lst, 1)
now the range of lst: [0 , 10018]
now the range of lst: [0 , 9]
loop times: 12
9
>>> GetNumberOfK(lst, 1)
loop times: 10010
9

>>> lst = [1]*9999 + [3]*10001
>>> GetNumberOfK_fst(lst, 3)
now the range of lst: [0 , 19999]
now the range of lst: [9999 , 19999]
loop times: 1
10001
>>> GetNumberOfK(lst, 3)
loop times: 9999
10001

"""

38、二叉樹的深度

38.1 思路

  • 思路:遞歸,左右遍歷取最長的

38.2 解題

def maxDepth(tree):
    if tree is None:
        return 0
    # 每遞歸計數一次
    return max(maxDepth(tree.left), maxDepth(tree.right)) + 1

from scc_function.Struct import BTree
btree = BTree(1, left = BTree(2, left=BTree(1), right=BTree(1))
               , right = BTree(2, left=BTree(1, left=BTree(1)), right=BTree(1)))

"""
>>> maxDepth(btree)
4
"""

39、平衡二叉樹

一個二叉樹每個節點 的左右兩個子樹的高度差的絕對值不超過1。

39.1 思路

  • 思路:遞歸

1- 利用39的求數深的函數求得左右子樹的深度
2- 比較兩者的差值,大於1爲非平衡樹

39.2 解題

def isBalanced(tree):
    if tree is None:
        return True
    elif abs(maxDepth(tree.left)-maxDepth(tree.right))>1:
        return False
    else:
        return  isBalanced(tree.left) and isBalanced(tree.right)

btree = BTree(1, left = BTree(2, left=BTree(1)
                               , right=BTree(1))
               , right = BTree(2, left=BTree(1
                                            , left=BTree(1,
                                                        left=BTree(1)))
                                , right=BTree(1)))
"""
>>> isBalanced(btree)
False
"""

40、數組中只出現一次的數字

一個整型數組裏除了兩個數字之外,其他的數字都出現了兩次。請寫程序找出這兩個只出現一次的數字

# 當只有一個數字不一樣的時候:
def FindNumsAppearOnce(lst):
    a = 0
    for num in lst:
        a ^= num
    return a

"""
>>> FindNumsAppearOnce([1,1,2,3,3,4,4])
2
"""

40.1 思路

  • 思路:遍歷

1- 字典遍歷並記錄
2- 最後在遍歷字典,將只出現一次的記錄列表,最後返回

40.2 解題

def FindNumsAppearOnce(lst):
    dct = {}
    res = []
    for i in lst:
        dct[i] = dct[i] + 1 if i in dct else 1
    for k, v in dct.items():
        if v == 1:
            res.append(k)
    return res
    
"""
>>> lst = [1,1,2,2,4,4,5,6,7,7,8,8]
>>> FindNumsAppearOnce(lst)
[5, 6]
"""

40.3 優化

參考:知乎-半情調:劍指offer-python版(下)

  • 思路:存在一個不一樣的數字的時候可以用異或,那麼分成兩個數組就能同樣的操作了

1- 找到拆分成兩個子列表的值(該數和其中一個目標數的併爲0)
1-1 異或之後末尾爲1,則兩個數的最右是不一樣的,即a & 1 == 1,這時候可以用1做拆分
1-2 異或之後末尾爲0, 則兩個數的最右是一樣的,即a & 1 == 0
這時候用1拆分就會存在問題,所以這時候需要向左移動直到找到 a & x == 1
2- 分兩組做異或

def FindNumsAppearOnce(lst):
    a = 0
    for num in lst:
        a ^= num
    splitBit = 1
    while splitBit & a == 0:
        splitBit = splitBit << 1
        print(splitBit)
    
    res1 = 0
    res2 = 0
    for i in lst:
        if i & splitBit == 0:
            res1 ^= i
        else:
            res2 ^= i
    return [res1,res2]

41、和爲S的連續正數序列

輸出所有和爲S的連續正數序列。序列內按照從小至大的順序,序列間按照開始數字從小到大的順序。

41.1 思路

  • 思路:雙指針偏移

1- 現在最小正數定下頭指針(1)和尾指針(2)
2- 比較當前和累計與目標值的大小
2-1 噹噹前累計等於目標值的時候輸出, 頭指針到尾指針的序列,尾指針後移,並加上後移的值
2-2 噹噹前累計大於目標值的時候, 頭指針後移,並減去之前的值
2-3 噹噹前累計小於目標值的時候, 尾指針後移,並加上後移的值
2-4 當頭指針到達目標值一半以上的時候停止

41.2 解題

def findlist(tsum):
    res = []
    i, j = 1, 2
    csum = i + j
    while i <= tsum/2:
        if csum == tsum:
            res.append(list(range(i, j+1)))
            j += 1
            csum += j
        elif csum > tsum:
            csum -= i
            i += 1
        else:
            j += 1
            csum += j
    return res 

"""
>>> findlist(30)
[[4, 5, 6, 7, 8], [6, 7, 8, 9], [9, 10, 11]]
"""

42、和爲S的兩個數字

輸入一個遞增排序的數組和一個數字S,在數組中查找兩個數,使得他們的和正好是S,如果有多對數字的和等於S,輸出兩個數的乘積最小的

42.1 思路

  • 思路:雙指針變量

1- 由於已經排好序,需要乘積最小,那麼兩者距離越遠乘積越小
2- 當頭+尾指針的和大於目標值的時候,移動尾指針
3- 當頭+尾指針的和小於目標值的時候,移動頭指針

41.2 解題

def FindNumbersWithSum(array, tsum):
    n = len(array)
    if n < 2:
        return []
    i = 0
    j = n - 1
    while i < j:
        if array[i] + array[j] > tsum:
            j -= 1
        elif array[i] + array[j] < tsum:
            i += 1
        else:
            return [array[i],array[j]]
    return []

"""
>>> FindNumbersWithSum([1,2,3,4,5,8], 6)
[1, 5]
"""

43、左旋轉字符

對於一個給定的字符序列S,請你把其循環左移K位後的序列輸出。例如,字符序列S=”abcXYZdef”,要求輸出循環左移3位後的結果,即“XYZdefabc”

43.1 思路

  • 思路:切片

43.2 解題

def leftturn(s, n):
    return  s[n:] + s[:n]

"""
>>> leftturn('abcXYZdef', 3)
'XYZdefabc'
"""

44、翻轉單詞順序列

例如,“student. a am I”翻轉爲“I am a student.”。

44.1 思路

  • 思路:split join

44.2 解題

def IsContinuous(s):
    s = s.split(' ')
    s.reverse()
    return ' '.join(s)

45、撲克牌順子

一副撲克牌,裏面有2個大王,2個小王,從中隨機抽出5張牌,如果牌能組成順子就輸出true,否則就輸出false。爲了方便起見,大小王是0,大小王可以當作任何數字。

45.1 思路

  • 思路:遍歷(共5張牌)

1- 找出大王小王的數量
2- 相鄰的相等False, 存在2返回False

45.2 解題

def IsContinuous(lst):
    """
    隨機抽5張牌
    """
    if not lst or lst==[]:
        return False
    
    trans_dct = {'J':11, 'Q':12, 'K':13, 'A':14  
                 ,'king_big':0,  'king_small':0
    }
    lst_deal = [trans_dct[i] if i in trans_dct else i for i in lst  ]
    lst_deal = sorted(lst_deal)
    king_cnt = 0
    while lst_deal[king_cnt] == 0:
        king_cnt += 1

    gap_cnt = 0
    for i in range(king_cnt, 4):
        if (lst_deal[i+1] == lst_deal[i]) or (lst_deal[i] == 2):
            return False
        gap_cnt += lst_deal[i+1] - lst_deal[i] - 1 # 相差1的不算間隙
    return True if gap_cnt <= king_cnt else False

"""
>>> IsContinuous(['J', 'Q', 'K', 'king_big', 2])
False
>>> IsContinuous(['J', 'Q', 'K', 'king_big', 'A'])
True
"""

46、孩子們的遊戲(圓圈中最後剩下的數)

遊戲是這樣的:首先,讓小朋友們圍成一個大圈。然後,他隨機指定一個數m,讓編號爲0的小朋友開始報數。每次喊到m-1的那個小朋友要出列,不再回到圈中,從他的下一個小朋友開始,繼續0…m-1報數…這樣下去…直到剩下最後一個小朋友獲勝,獲勝的小朋友編號多少?(注:小朋友的編號是從0到n-1)

46.1 思路

  • 思路:求餘

移動位置求餘 來排除

46.2 解題

def LastRemaining_Solution(n, m):
    if not n and not m :
        return -1
    
    lst = list(range(n))
    i = 0
    while len(lst) > 1:
        # 移動位置求餘
        i = (m-1 + i) % len(lst) 
        lst.pop(i)
    return lst[0]


"""
>>> LastRemaining_Solution(5, 3)
3
"""

47、求1+2+3+…+n

求1+2+3+…+n,要求不能使用乘除法、for、while、if、else、switch、case等關鍵字及條件判斷語句(A?B:C)。

47.1 思路

  • 思路:遞歸

47.2 解題

def Sum_Solution(n):
    """
    不能使用乘除法,
    使用if else來確定終止條件
    利用and來實現遞歸的終止
    """
    return n and n + Sum_Solution(n-1)

"""
>>> Sum_Solution(100)
5050
"""

48、不用加減乘除做加法

寫一個函數,求兩個整數之和,要求在函數體內不得使用+、-、*、/四則運算符號。

48.1 思路

  • 思路:位運算

1-可以考慮將加法分成兩部分 (1)0+1 = 1 1+0 = 1; (2) 0+0=0 1+1=10
2- (1)部分的運算其實和 ^ (異或一致) 01|10-> 1 00|11->0
3- (2)部分可以分解成 & + << 00-> 0 << 1 -> 00; 11-> 1 << 1 -> 10
4- 循環直到(2)部分的數爲0

48.2 解題

def Add(num1, num2):
    while num2 !=0:
        sum_ = num1 ^ num2
        sum_add = (num1 & num2) << 1
        num1 = sum_
        num2 = sum_add
    return sum_


"""
>>> Add(100,1000)
1100
"""

48.3 優化

知乎博主指出python的負數相加需要特殊處理,否則會陷入死循環
在早期版本中如Python2.7中,整數的有int和long兩個類型。int類型是一個固定位數的數;long則是一個理論上可以存儲無限大數的數據類型。當數大到可能溢出時,爲了避免溢出,python會把int轉化爲long。而Python3.x之後整數只有一個可以放任意大數的int了。可是無論哪種,都是採用了特殊的方法實現了不會溢出的大整數。 所以會使程序無限的算下去,這也是Python效率低的一個原因。(python2和python3都有這個問題。)
已經知道了右移過程中大整數的自動轉化,導致變不成0,那麼只需要在移動的過程中加一下判斷就行了,把sum_add的值和0xFFFFFFFF做一下比較就可以了,具體代碼如下所示

def Add(num1, num2):
    while num2 !=0:
        sum_ = num1 ^ num2
        sum_add = 0xFFFFFFFF&(num1 & num2)<<1
        sum_add = -(~(sum_add - 1) & 0xFFFFFFFF) if sum_add > 0x7FFFFFFF else sum_add
        num1 = sum_
        num2 = sum_add
    return sum_

"""
>>> Add(100,-1)
99
"""

49、把字符串轉換成整數

將一個字符串轉換成一個整數(實現Integer.valueOf(string)的功能,但是string不符合數字要求時返回0),
要求不能使用字符串轉換整數的庫函數。 數值爲0或者字符串不是一個合法的數值則返回0。

49.1 思路

  • 思路:int

1- 先去除兩邊空值,然後判斷正負
2- 用try except輸出

49.2 解題

def StrToInt(s):
    s = s.strip()
    if not s:
        return 0
    symbol = 1
    if s[0] == '-':
        s = s[1:]
        symbol = -1
    if s[0] == '+':
        s = s[1:]
    num_dct = {'0': 0, '1': 1, '2': 2, '3': 3, '4': 4, '5': 5, '6': 6, '7': 7, '8': 8, '9': 9}
    out_num = 0
    n = 1
    for i in s[::-1]:
        if i in num_dct:
            out_num += n * num_dct[i]
            n *= 10
        else:
            return 0
    return  out_num * symbol
    
## 可以直接用int 在內會自己判斷

def StrToInt(s):
    try:
        return  int(s)
    except:
        return  0

50、數組中重複的數字

在一個長度爲n的數組裏的所有數字都在0到n-1的範圍內。 數組中某些數字是重複的,但不知道有幾個數字是重複的。
也不知道每個數字重複幾次。請找出數組中任意一個重複的數字。
例如,如果輸入長度爲7的數組{2,3,1,0,2,5,3},那麼對應的輸出是第一個重複的數字2。

50.1 思路

  • 思路:字典+遍歷

1- 當某個數字出現了兩次就停止

50.2 解題

def duplicate(numbers, duplication):
    cnt_dct = {}
    loop_n = 0
    # 僅僅當某個數字出現2次就停止
    for i in numbers:
        cnt_dct[i] = cnt_dct.get(i,0) + 1
        if cnt_dct[i] > 1:
            duplication[0] = i
            print(f'獲取重複數字循環了:{loop_n}次')
            return True
        loop_n += 1
    print(f'獲取重複數字循環了:{loop_n}次')
    return False

50.3 優化解題

  • 雙指針遍歷
def duplicate_qk(numbers, duplication):
    cnt_dct = {}
    loop_n = 0
    n = len(numbers)
    i, j = 0, n - 1
    # 僅僅當某個數字出現2次就停止
    while i < j:
        num_i, num_j = numbers[i], numbers[j]
        cnt_dct[num_i] = cnt_dct.get(num_i, 0) + 1
        cnt_dct[num_j] = cnt_dct.get(num_j, 0) + 1
        if cnt_dct[num_i] > 1:
            duplication[0] = num_i
            print(f'獲取重複數字循環了:{loop_n}次')
            return True
        if cnt_dct[num_j] > 1:
            duplication[0] = num_j
            print(f'獲取重複數字循環了:{loop_n}次')
            return True
        i += 1
        j -= 1
        loop_n += 1
    print(f'獲取重複數字循環了:{loop_n}次')
    return False
  • 測試比較
import numpy as np
for _ in range(5):
    # 產生20000個0-10000的隨機數列表
    hundred_lst = list(range(0,10000))
    hundred_lst_plus = hundred_lst * 2
    np.random.shuffle(hundred_lst_plus)

    lst = [0]
    print('\n', '--'*20)
    print('單指針:')
    a = duplicate(hundred_lst_plus, lst)
    print('雙指針:')
    b = duplicate_qk(hundred_lst_plus, lst)
   
"""
 ----------------------------------------
單指針:
獲取重複數字循環了:154次
雙指針:
獲取重複數字循環了:46次

 ----------------------------------------
單指針:
獲取重複數字循環了:230次
雙指針:
獲取重複數字循環了:27次

 ----------------------------------------
單指針:
獲取重複數字循環了:80次
雙指針:
獲取重複數字循環了:80次

 ----------------------------------------
單指針:
獲取重複數字循環了:326次
雙指針:
獲取重複數字循環了:169次

 ----------------------------------------
單指針:
獲取重複數字循環了:70次
雙指針:
獲取重複數字循環了:70次
"""

51、構建乘積數組

給定一個數組A[0,1,…,n-1],請構建一個數組B[0,1,…,n-1],其中B中的元素B[i]=A[0]* A[1]* …* A[i-1]* A[i+1]* …* A[n-1]。不能使用除法。

51.1 思路

  • 思路:遍歷

1- 每一位都進行遍歷

51.2 解題

# 構建乘積數組
def multiply(lst):
    len_ = len(lst)
    res_out = []
    # 構建一個累積的數據
    for index_r in  range(len_):
        res = 1
        for index_ in  range(len_):
            if  index_ == index_r:
                continue
            res *= lst[index_]
        res_out.append(res)

    return res_out

multiply([1, 2, 3])

51.3 解題2

def multiply_2(lst):
    all_mult = 1
    for i in  lst:
        all_mult *= i
    
    res_out = []
    for num in lst:
        sign_ = (all_mult > 0) ^(num > 0)
        a, b = abs(num), abs(all_mult)
        # 獲取第一次向左移動的位數
        cnt = 0
        while a <= b:
            a <<= 1
            cnt += 1
        
        # 開始計算'除法'
        res_num = 0
        while cnt > 0:
            a >>= 1
            cnt -= 1
            if a <= b:
                res_num += 1 << cnt
                b -= a
        # 獲取除後的數
        res_out.append(-res_num if sign_ else res_num)
    return res_out

"""
>>> multiply_2([1, 2, -3])
[-6, -3, 2]
>>> multiply([1, 2, -3])
[-6, -3, 2]
"""

52、正則表達式匹配

請實現一個函數用來匹配包括’.‘和’ * ’ 的正則表達式。模式中的字符’.‘表示任意一個字符,而’ * '表示它前面的字符可以出現任意次(包含0次)。 在本題中,匹配是指字符串的所有字符匹配整個模式。例如,字符串"aaa"與模式"a.a"和"ab * ac * a"匹配,但是與"aa.a"和"ab * a"均不匹配。

52.1 思路

  • 思路:遞歸

1- 當text與parttern一致時返回True, 當pattern爲空時, 返回 not text
2- 將’.‘與其他字母一併判斷,並結合text是否爲空
3- 發現並處理’*’ ,分兩種情況後移,1) pattern後移兩位,2) text後移一位

52.2 解題

def isMatch(text, pattern) -> bool:
    if  text == pattern:
        return True
    if not pattern:
        return not text
    match = bool(text) and pattern[0] in {'.', text[0]}
    if len(pattern) >=2 and pattern[1] == '*':
        # 匹配該字符0次,然後跳過該字符和'*', 一般在最後判斷的時候(text已經爲空) 
        # 當 pattern[0] 與 text[0]匹配後 後移 text
        return isMatch(text, pattern[2:]) or\
            (match and isMatch(text[1:], pattern))
    return match and isMatch(text[1:], pattern[1:])

"""
>>> isMatch('asdasd', 'a.*')
True
"""

53、表示數值的字符串

請實現一個函數用來判斷字符串是否表示數值(包括整數和小數)。例如,字符串"+100",“5e2”,"-123",“3.1416"和”-1E-16"都表示數值。 但是"12e",“1a3.14”,“1.2.3”,"±5"和"12e+4.3"都不是。

53.1 思路

  • 思路:float

53.2 解題


def isNumeric(self, s):
    try:
        s = float(s)
        return True
    except:
        return False

54、字符流中第一個不重複的字符

請實現一個函數用來找出字符流中第一個只出現一次的字符。例如,當從字符流中只讀出前兩個字符"go"時,第一個只出現一次的字符是"g"。當從該字符流中讀出前六個字符“google"時,第一個只出現一次的字符是"l"。
如果當前字符流沒有存在出現一次的字符,返回#字符。

54.1 思路

  • 思路:dct + 雙指針遍歷 (類似 50、數組中重複的數字)

54.2 解題

def FirstAppearingOnce(s):
    cnt_dct = {}
    n = len(s)
    i, j = 0, n - 1
    while i <= j:
        s_i, s_j = s[i], s[j]
        cnt_dct[s_i] = cnt_dct.get(s_i, 0) + 1
        cnt_dct[s_j] = cnt_dct.get(s_j, 0) + 1
        if i == j:
            cnt_dct[s_j] = cnt_dct.get(s_j, 0) - 1
        i += 1
        j -= 1
    
    for i in s:
        if cnt_dct[i] == 1:
            return i
    return '#'

"""
>>> FirstAppearingOnce('gooogle')
{'g': 2, 'e': 1, 'o': 3, 'l': 1}
'l'
"""
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章