[C++]LeetCode: 47 Anagrams

题目:

Given an array of strings, return all groups of strings that are anagrams.

Note: All inputs will be in lower-case.

For example:

Input:  ["tea","and","ate","eat","den"]

Output:   ["tea","ate","eat"]

Interface: vector<string>anagrams(vector<string>&strs);

A:

首先简单介绍一下Anagram(回文构词法)。Anagrams是指由颠倒字母顺序组成的单词,比如“dormitory”颠倒字母顺序会变成“dirty room”,“tea”会变成“eat”。

回文构词法有一个特点:单词里的字母的种类和数目没有改变,只是改变了字母的排列顺序。

由此我们可以想到,只要将几个单词按照字母顺序进行排序,就可以通过比较判断他们是否是anagrams。


Answer 1: 使用unordered_multimap

思路:将字符串重新排序(sort),并把所有排序后的字符串存入multi_Map。之后利用equal_range()检索所有同key的字符串。之后存入到结果中。

背景知识:

1. equal_range():返回同key的一个迭代器的pair对象(element从first到last+1。该键关联的第一个实例,以及该键关联的最后一个实例的下一个位置)。如果找不到匹配的元素,pair对象中的两个迭代器都指向此键应该插入的位置。

equal_range()迭代: its.first 代表first元素, its.second 代表last+1元素。

auto its = map.equal_range('a');
for (auto it = its.first; it != its.second; ++it) {
    cout << it->first << '\t' << it->second << endl;
}
2. map<k, v>::value_type: 返回一个pair类型,first元素对应const map<k,v>::key_type类型(键),second元素对应map<k,v>::mapped_type类型(值)(值可以修改,但是key不能修改)

map_it->first 取key; map_it->second 取value.

3. auto:

在C++11标准之前,auto关键字就被用来标识临时变量语义,在新的标准中,它的目的变成了另外两种用途。auto现在是一种类型占位符,它会告诉编译器,应该从初始化式中推断出变量的实际类型。当你想在不同的作用域中(例如,命名空间、函数内、for循环中中的初始化式)声明变量的时候,auto可以在这些场合使用。

auto i = 42;        // i is an int
auto l = 42LL;      // l is an long long
auto p = new foo(); // p is a foo*

使用auto经常意味着较少的代码量(除非你需要的类型是int这种只有一个单词的)。当你想要遍历STL容器中元素的时候,想一想你会怎么写迭代器代码,老式的方法是用很多typedef来做,而auto则会大大简化这个过程。

std::map<std::string, std::vector<int>> map;
for(auto it = begin(map); it != end(map); ++it) 
{
}

你应该注意到,auto并不能作为函数的返回类型,但是你能用auto去代替函数的返回类型,当然,在这种情况下,函数必须有返回值才可以。auto不会告诉编译器去推断返回值的实际类型,它会通知编译器在函数的末段去寻找返回值类型。在下面的那个例子中,函数返回值的构成是由T1类型和T2类型的值,经过+操作符之后决定的。

template <typename T1, typename T2>
auto compose(T1 t1, T2 t2) -> decltype(t1 + t2)
{
   return t1+t2;
}
auto v = compose(2, 3.14); // v's type is double
4. std::unordered_multimap::count

size_type count (const key_type& k) const;

返回与关键 key的元素的数目.



AC Code:

class Solution {
public:
    vector<string> anagrams(vector<string> &strs) {
        
        vector<string> res;
        if(strs.size() < 2) return res;
        
        unordered_multimap<string, int> collections;
        //put everything into multimap
        for(int i = 0; i < strs.size(); i++)
        {
            string s = strs[i];
            //将字符串sort,如果是回文字符key值会一样。
            sort(s.begin(), s.end());
            collections.insert({s, i});
        }
        
        //loop over unique key
        auto it = collections.begin();
        while(it != collections.end())
        {
            string s = it->first;
            //size_type count (const key_type& k) const;
            if(collections.count(s) > 1)
            {
                auto range = collections.equal_range(s);
                for(auto it = range.first; it != range.second; it++)
                {
                    //按照对应的字符串索引添加到ret,it是迭代器,it->second代表map的key对应的value
                    res.push_back(strs[it->second]);
                }
            }
            //让迭代器指向当前同key范围的下一个迭代器,即键大于k的第一个元素
            it = collections.equal_range(s).second;
        }
        
        return res;
    }
};

Answer 2:  使用unordered_map

思路:map<string, int>记录排序后的字符串以及首次出现的位置。

1. 从strs的第一个元素开始遍历,首先对元素进行排序得到s

2. 在map里查找s

3. 若不存在,将s以及该元素的下标存入map<string ,int>

4. 若存在,首先将第一次出现s时的原始字符串存入结果res,即strs[map[s]],并将map[s]设置为-1(防止下次再存),再将该字符串本身存入结果res

5. 重复以上1-4步,直到遍历结束。

AC Code:
class Solution {
public:
    vector<string> anagrams(vector<string> &strs) {
        vector<string> res;
        if(strs.size() < 2) return res;
        
        unordered_map<string, int> cache;
        for(int i = 0; i < strs.size(); i++)
        {
            string s = strs[i];
            sort(s.begin(), s.end());
            auto it = cache.find(s);
            
            if(it == cache.end())
            {
                cache.insert({s, i});
            }
            else
            {
                //存储当前回文字符串
                res.push_back(strs[i]);
                if(it->second >= 0)
                {
                    //第一次出现s时的原始字符串存入结果res,并且置为-1,防止重复写入
                    res.push_back(strs[it->second]);
                    it->second = -1;
                }
            }
        }
        
        return res;
    }
};
本题其实降低了一点难度,就是输入的字符串全部为小写字母,这样就不需要处理大写字母,空格这些特殊情况了。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值