本题为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 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  1 and word[p1] == '0': # 移动左指针去除前导0                p1 += 1                        hashset.add(word[p1:p2]) # 切分出数字部分,放入集合中            p1 = p2 # 移动左指针        return len(hashset)

“正是我们每天反复做的事情,最终造就了我们,优秀不是一种行为,而是一种习惯” —亚里士多德

这里是浙江理工大学22届ACM集训队的成员一枚鸭!

本文首发于博客园,作者:星双子,除了我自己的转载请注明原文链接:https://www.cnblogs.com/geministar/p/LeetCode1805.html