LeetCode之路:389. Find the Difference

一、引言

最近几天工作很忙,好不容易闲下来了,来看看这道“惬意”的小题:

Given two strings s and t which consist of only lowercase letters.

String t is generated by random shuffling string s and then add one more letter at a random position.

Find the letter that was added in t.

Example:

Input:
s = “abcd”
t = “abcde”

Output:
e

Explanation:
‘e’ is the letter that was added.

看起来英文解释好像比较多,但是结合实例我们来看看,其实也就是一句话就可以讲清楚的题:s 和 t 都是只含有小写字母的字符串,其中 t 中的内容是 s 中的所有的字母打乱后再随机添加了一个字母,让你找到这个随机添加的字母。

看到这道题,浮现在我脑海里的第一想法有很多,接下来我们来慢慢梳理。

二、使用 std::map

首先,在我们明确了题意之后,我们能够明白一点,这里有两个数组,并且我们需要找到 t 数组相对于 s 数组中多出来的那一个。

那么该怎么做呢?

很容易就会想到 map 对不对?

是啊,我们只需要遍历 s 出一个 s_map,遍历 t 出一个 t_map, 那么再遍历元素多一个的 t 数组,取出每个元素来分别在 s_map 和 t_map 中查询出现次数,出现次数不同的字母即为多添加的字母。

说的已经很详细了,代码如下:

// my solution 1 , runtime = 6 ms
class Solution1 {
public:
    char findTheDifference(string s, string t) {
        map<char, int> s_map;
        map<char, int> t_map;
        for (auto c : s) {
            ++s_map[c];
        }
        for (auto c : t) {
            ++t_map[c];
        }
        for (auto c : t) {
            if (t_map[c] != s_map[c]) {
                return c;
            }
        }
    }
};

我们提交后,看到 runtime 为 6 ms。

接下来,我们来一起想想,如何降低 runtime?

比如将有序的 map 更换为无序的 unordered_map 试试:

// my solution 2 , runtime = 6 ms
class Solution2 {
public:
    char findTheDifference(string s, string t) {
        unordered_map<char, int> s_map;
        unordered_map<char, int> t_map;
        for (auto c : s) {
            ++s_map[c];
        }
        for (auto c : t) {
            ++t_map[c];
        }
        for (auto c : t) {
            if (t_map[c] != s_map[c]) {
                return c;
            }
        }
    }
};

非常遗憾,这里发现 runtime 是一样的,可能是根据具体的 case 有关,很显然这里使用这个方法降低 runtime 是不可行的。

那么,让我们想想其他的办法。

三、使用 std::set

这时候,我想到了 std::set ,我记得 std::set 好像有一个 count 方法,我们来看看可不可以降低 runtime:

// my solution 4 , failed
// std::set::count or std::unordered_set::count 
// value only equals to 0 or 1
class Solution4 {
public:
    char findTheDifference(string s, string t) {
        set<char> s_set(s.cbegin(), s.cend());
        set<char> t_set(t.cbegin(), t.cend());
        for (auto c : t) {
            if (s_set.count(c) != t_set.count(c)) {
                return c;
            }
        }
    }
};

编译代码,发现 case 跑出了错误!

为什么呢?我们像上面的处理 std::map 的逻辑一样,怎么会出错了呢?

我查找了下 C++ 在线手册,才发现原来 std::set::count 方法的返回值只能为 0 或者 1。也就是说,我们这里想要通过 std::set 来计数字母出现次数的做法,是错误的。

那么,我们该如何降低 runtime 呢?

四、char 其实是个数字而已

要想降低 runtime ,就必须更换思路,上面的思路我们已经走到了性能极限了。

让我们想想,char ,char, char 类型的字母…

想到了什么没?

XOR!Is always the trick!

我在做 LeetCode 第 136 题 Single Number 的时候,当看到最优解的时候内心的想法跟这句话是一样的!(想要了解这道题的仁兄可以点击这里LeetCode之路:136. Single Number)。

对呀!我们可以使用异或啊!

想想,s 中的字母在 t 中全部都有,那么 s 中的字母跟 t中的字母全部异或后,结果肯定为 0 异或t中增加的那个字母值。

代码很简单:

// my solution 5 , perfect runtime = 3 ms
class Solution5 {
public:
    char findTheDifference(string s, string t) {
        char c = '\0';
        for (auto s_c : s) {
            c ^= s_c;
        }
        for (auto t_c : t) {
            c ^= t_c;
        }
        return c;
    }
};

看了看 Discuss,看到了最高票答案也是这个思路,深深的自豪感油然而生。

3ms

只要我们认认真真做每一道题,认认真真思考每一道题的最优解,那么总有一天,我们也会做出来让别人瞠目结舌的最优解!

rank

五、总结

这确实是一道非常简单的题目,最优解使用了 XOR 异或,不过中间从 std::map 到 std::unordered_map 的尝试,从 std::unordered_map 再到 std::set 的尝试,无一不是在夯实自己的逻辑思维和编程基础。

永远保持着对于最优解的好奇心;
永远保持着对于奇妙解法的探索心;
总有一天,我们都会成为别人眼中的大神的!

I code,I fly!
I believe!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值