劍指offer 52、53、54

2020-08-13 16:38:42

52、正則表達式匹配

在这里插入图片描述

解這題需要把題意仔細研究清楚,反正我試了好多次才明白的。
首先,考慮特殊情況:
     1>兩個字串都爲空,返回true
     2>當第一個字串不空,而第二個字串空了,返回false(因爲這樣,就無法
        匹配成功了,而如果第一個字串空了,第二個字串非空,還是可能匹配成
        功的,比如第二個字串是「a*a*a*a*」,由於‘*’之前的元素可以出現0次,
        所以有可能匹配成功)
之後就開始匹配第一個字元,這裏有兩種可能:匹配成功或匹配失敗。但考慮到pattern
下一個字元可能是‘*’, 這裏我們分兩種情況討論:pattern下一個字元爲‘*’或
不爲‘*’:
      ①pattern下一個字元不爲‘*’:這種情況比較簡單,直接匹配當前字元。如果
        匹配成功,繼續匹配下一個;如果匹配失敗,直接返回false。注意這裏的
        「匹配成功」,除了兩個字元相同的情況外,還有一種情況,就是pattern的
        當前字元爲‘.’,同時str的當前字元不爲‘\0’。
      ②pattern下一個字元爲‘*’時,稍微複雜一些,因爲‘*’可以代表0個或多個。
        這裏把這些情況都考慮到:
           a>當‘*’匹配0個字元時,str當前字元不變,pattern當前字元後移兩位,
            跳過這個‘*’符號;
           b>當‘*’匹配1個或多個時,str當前字元移向下一個,pattern當前字元
            不變。(這裏匹配1個或多個可以看成一種情況,因爲:當匹配一個時,
            由於str移到了下一個字元,而pattern字元不變,就回到了上邊的情況a;
            當匹配多於一個字元時,相當於從str的下一個字元繼續開始匹配)
之後再寫程式碼就很簡單了。
# -*- coding:utf-8 -*-
class Solution:
    # s, pattern都是字串
    def match(self, s, pattern):
        # 如果s與pattern都爲空,則True
        if len(s) == 0 and len(pattern) == 0:
            return True
        # 如果s不爲空,而pattern爲空,則False
        elif len(s) != 0 and len(pattern) == 0:
            return False
        # 如果s爲空,而pattern不爲空,則需要判斷
        elif len(s) == 0 and len(pattern) != 0:
            # pattern中的第二個字元爲*,則pattern後移兩位繼續比較
            if len(pattern) > 1 and pattern[1] == '*':
                return self.match(s, pattern[2:])
            else:
                return False
        # s與pattern都不爲空的情況
        else:
            # pattern的第二個字元爲*的情況
            if len(pattern) > 1 and pattern[1] == '*':
                # s與pattern的第一個元素不同,則s不變,pattern後移兩位,相當於pattern前兩位當成空
                if s[0] != pattern[0] and pattern[0] != '.':
                    return self.match(s, pattern[2:])
                else:
                    # 如果s[0]與pattern[0]相同,且pattern[1]爲*,這個時候有三種情況
                    # pattern後移2個,s不變;相當於把pattern前兩位當成空,匹配後面的
                    # pattern後移2個,s後移1個;相當於pattern前兩位與s[0]匹配
                    # pattern不變,s後移1個;相當於pattern前兩位,與s中的多位進行匹配,因爲*可以匹配多位
                    return self.match(s, pattern[2:]) or self.match(s[1:], pattern[2:]) or self.match(s[1:], pattern)
            # pattern第二個字元不爲*的情況
            else:
                if s[0] == pattern[0] or pattern[0] == '.':
                    return self.match(s[1:], pattern[1:])
                else:
                    return False

53、表示數值的字串

在这里插入图片描述
解題思路:

  • 12e說明e的後面必須有數位,不能有兩個e
  • ±5說明符號位要麼出現一次在首位,要麼出現一次在e的後一位,其他地方都不能有
  • 12e4.3說明e的後面不能有小數,1.2.3說明不能有兩個小數點
  • 1a3.14說明不能有其他的非法字元,比如這裏的a

解法:
這題難點只有邊界問題的考慮,所以最好一開始就考慮全麪點,省的不斷的調bug,給面試官不好的印象。
那麼結合上圖中給的提示,大概有以下幾種情況:

  1. e/E之前和e/E之後可以看做是兩個部分。

  2. e/E之前的部分:
    +/-只能在頭部出現,且只能出現一次;
    數位直接continue
    非e/E的字元出現,直接return False
    頭部如果出現".",直接return False
    非頭部如果出現一次".",後面如果再出現".",則return False

  3. e/E之後的部分:
    +/-只能在頭部出現,且只能出現一次;
    如果有".",直接return False
    如果觸發e/E之後的部分,e/E後沒有其他數位了,要return False
    其他符號也要return False

以上即爲全部的邊界條件,通過多個flag去進行控制。

# -*- coding:utf-8 -*-
class Solution:
    # s字串
    def isNumeric(self, s):
        # write code here
        flag = 0  # 是否有e/E,預設沒有爲0
        _flag = 0  # e/E後的加/減號的flag
        dot_flag = 0  # e/E前的「.」的flag
        
        i = 0
        count = 0  # 判斷觸發e/E後是否仍有數位
        if s[i] == '+':
            i += 1
        elif s[i] == '-':
            i += 1
        elif s[i] == '.':  # 頭部如果出現".",直接return False
            return False

        for item in s[i:]:
            if flag == 0:  # e/E之前的部分
                if dot_flag == 1 and item == '.':
                    return False
                if '0' <= item <= '9':  # 數位直接continue
                    continue
                if item == 'e' or item == 'E':  # 觸發e/E後的部分
                    flag = 1
                    continue
                if item == '.':
                # 非頭部如果出現一次".",後面如果再出現".",則return False
                    dot_flag = 1
                    continue
                else:
                    return False
            else:
                count += 1
                # 如果觸發e/E之後的部分,e/E後沒有其他數位了,要return False
                if _flag == 1 and (item == '-' or item == '+'):
                # +/-只能在頭部出現,且只能出現一次;
                    return False
                if item == '+':
                    _flag = 1
                    continue
                if item == '-':
                    _flag = 1
                    continue
                if item == '.':  # 有"."直接False
                    return False
                if '0' <= item <= '9':
                    continue
                else:
                    return False
        if flag == 1 and count == 0:
            return False
        return True

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

在这里插入图片描述
Python中,lambda函數也叫匿名函數,及即沒有具體名稱的函數,它允許快速定義單行函數,類似於C語言的宏,可以用在任何需要函數的地方。這區別於def定義的函數。
filter 表示過濾器

# -*- coding:utf-8 -*-
class Solution:
    def __init__(self):
        self.s = ""
    # 返回對應char
    def FirstAppearingOnce(self):
        # write code here
        res = list(filter(lambda x:self.s.count(x)==1, self.s))
        if res:
            return res[0]
        else:
            return "#"
        # return res [0] if res else "#"
    def Insert(self, char):
        # write code here
        self.s += char