1. 程式人生 > 其它 >「查詢表」字串中不同整數的數目(力扣第1805題)

「查詢表」字串中不同整數的數目(力扣第1805題)

本題為12月6日力扣每日一題

題目來源:力扣第1805題

題目tag:查詢表 雙指標

題面

題目描述

給你一個字串word,該字串由數字和小寫英文字母組成。

請你用空格替換每個不是數字的字元。例如,"a123bc34d8ef34"將會變成" 123  34 8  34"。注意,剩下的這些整數為(相鄰彼此至少有一個空格隔開):"123"、"34"、"8" 和 "34" 。

返回對word完成替換後形成的不同整數的數目。

只有當兩個整數的不含前導零的十進位制表示不同,才認為這兩個整數也不同。

示例

示例 1

輸入:

word = "a123bc34d8ef34"

輸出:

3

解釋:

不同的整數有 "123"、"34" 和 "8" 。注意,"34" 只計數一次。

示例 2

輸入:

word = "leet1234code234"

輸出:

2

示例 3

輸入:

word = "a1b01c001"

輸出:

1

解釋:

"1"、"01" 和 "001" 視為同一個整數的十進位制表示,因為在比較十進位制值時會忽略前導零的存在。

提示

1 <= word.length <= 1000
word 由數字和小寫英文字母組成


思路分析

顯然,這道題只需要我們提取出給定字串中的數字,然後統計有幾個不重複的即可.

判斷有幾個不重複只需要一個能進行高效的搜尋與插入的資料結構即可,二叉查詢樹雜湊集等均可勝任,可以根據語言自身提供的庫進行選擇(C++中我選擇unordered_set

)

這題的一大坑點在於,數字的長度可能會超過整數型別的表示範圍(Python玩家可無視),所以不能直接將提取出來的數字轉化成整數,必須仍然使用字串來表示.

而用字串表示的整數,其前導零不會被去除,所以這題唯一的難點應該是處理前導0了.對此有很多種辦法,比如提取數字時使用雙指標分別指向數字的開頭和結尾,然後移動前面的指標去掉開頭的零,再提取子串即可.由於不同語言對字串的實現不同,所以一些做法可能不能通用.

在C++中,字串是可變的(Java中可以使用StringBuilder類的例項物件達到同樣的效果),所以我個人的做法是在遍歷時,將遇到的數字拼接成一個字串,如果拼接時當前用來拼接的字串裡面放著0,那麼就將其覆蓋,這樣就可以去掉開頭的零了.對於String不可變的語言,這樣可能會產生大量的無用物件,引起空間浪費,所以還是建議使用上述的雙指標做法(見Python程式碼)

參考程式碼

拼接字串法(語言需要字串可變,Java可用StringBuilder):

class Solution
{
public:
    int numDifferentIntegers(string word)
    {
        word += '.';                   // 手動在最後加一個字元,代替對尾部的特判
        unordered_set<string> hashset; // 記錄不重複的數字
        string num = "";               // 不可用整數型別,可能會超出範圍
        bool flag = false;             // 標記當前是否正在拼接
        for (auto c : word)
        {
            if (c >= '0' && c <= '9')
            {
                flag = true;
                if (num == "0") // 當前只有一個0,證明是前導0,將其覆蓋
                {
                    num = c;
                }
                else // 沒有前導0了,拼接
                {
                    num += c;
                }
            }
            else if (flag) // 遇到字元,拼接結束
            {
                flag = false;
                hashset.insert(num); // unordered_set本身不會重複,所以可以自動去重
                num = "";
            }
        }
        return hashset.size();
    }
};

雙指標法:

class Solution(object):
    def numDifferentIntegers(self, word):
        """
        :type word: str
        :rtype: int
        """
        hashset = set() # 儲存不重複資料的集合
        n = len(word)

        p1 = 0 # 左指標
        while p1 != n:
            while p1 < n and not word[p1].isdigit(): # 移動左指標到數字
                p1 += 1
            if p1 == n:
                break
            
            p2 = p1 # 右指標
            while p2 < n and word[p2].isdigit(): # 移動右指標到數字邊界(前閉後開)
                p2 += 1
            
            while p2 - p1 > 1 and word[p1] == '0': # 移動左指標去除前導0
                p1 += 1
            
            hashset.add(word[p1:p2]) # 切分出數字部分,放入集合中
            p1 = p2 # 移動左指標
        return len(hashset)

"正是我們每天反覆做的事情,最終造就了我們,優秀不是一種行為,而是一種習慣" ---亞里士多德