HashMap在寻找回文串中的使用

336. 回文对

首先想出蛮力算法

  1. 所谓蛮力算法,就是枚举每一个字符串,然后判断他们加起来是不是一个回文。

  2. 这个方法的代码如下,我看题解里有人说在别的语言中使用蛮力算法是可以通过的,但是C++中使用蛮力算法就会超时,但是通过蛮力算法来启发思路还是蛮不错的。

  3. 时间复杂度O(n^2 * m), m为字符串平均长度

class Solution {
public:
    //蛮力算法
    vector> palindromePairs(vector& words) {
        vector> sto;
        for (int i(0); i < words.size(); i++)
            for (int j(0); j < words.size(); j++) {
                if (i == j) continue;
                if (isPalindrome(words[i], words[j]))
                    sto.push_back({i, j});
            }
        return sto;
    }

    bool isPalindrome(string a, string b) {
        string all = a + b;
        for (int i(0); i < all.size(); i++) {
            if (*(all.begin() + i) != *(all.end() - i - 1))
                return false;
        }
        return true;
    }
};

使用HaspMap来进行优化

  1. 对于两个字符串a和b而言,有三种可能。
    1. len(a) == len(b):这种情况下a是b的翻转
    2. len(a) > len(b):这种情况下,a是可以拆分成两部分的,一部分自己就是一个回文,另一部分可能是其他字符串的回文,我们需要做的就是找到这个其他的字符串。
    3. len(a) < len(b):同上。
  2. 思路:我们枚举字符串的每一个前缀和后缀,判断其是否为回文串。如果是回文串,我们就查询其剩余部分的翻转是否在给定的字符串序列中出现即可。
  3. 所以,我们就需要一个存储翻转字符串的数据结构,这里使用HashMap,还有一个字典树的做法,我没有搞懂。
  4. 代码如下,和官方的是差不多的,我根据自己的理解添加了些许注释,希望对你有帮助。
  5. 时间复杂度:O(n * m^2)
class Solution {
private:
    vector wordsRev;
    unordered_map indices;
public:
    //在indices中寻找前缀(在indices中本来就是倒序的,如果找到和前缀一样的了,就说明找到倒序的了)
    int findWord(const string_view& s, int left, int right) {
        auto iter = indices.find(s.substr(left, right - left + 1));
        return iter == indices.end()? -1: iter->second;
    }
    //判断当前string_view是否是回文
    bool isPalindrome(const string_view& s, int left, int right) {
        int len = right - left + 1;
        for (int i(0); i < len / 2; i++)
            if (s[left + i] != s[right - i])
                return false;
        return true;
    }

    vector> palindromePairs(vector& words) {
        int n = words.size();
        //将每一个word进行翻转,并存放在wordsRev
        for (const string& word: words) {
            wordsRev.push_back(word);
            reverse(wordsRev.back().begin(), wordsRev.back().end());
        }
        //将翻转后的字符串放到indices中
        for (int i(0); i < n; i++)
            indices.emplace(wordsRev[i], i);

        //用于存放返回结果
        vector> ret;
        for(int i(0); i < n; i++) {
            int m = words[i].size();
            if (!m) continue;   //如果当前word的长度为0,则继续
            //使用string_view可以避免频繁的字符串拷贝
            string_view wordView(words[i]);
            for (int j(0); j <= m; j++) {
                //如果后缀是回文,就去indices里面寻找前面的剩余部分
                if (isPalindrome(wordView, j, m - 1)) {
                    int left_id = findWord(wordView, 0, j - 1);
                    //剩余部分的字符串在indices中存在同时也不是自己
                    if (left_id != -1 && left_id != i)
                        ret.push_back({i, left_id});
                }
                //如果前缀是回文,那就去找后缀
                if (j && isPalindrome(wordView, 0, j - 1)) {
                    int right_id = findWord(wordView, j, m - 1);
                    if (right_id != -1 && right_id != i)
                        ret.push_back({right_id, i});
                }
            }
        }
        return ret;
    }
};

你可能感兴趣的:(刷题总结)