leetcode:267. 回文排列 II

题目来源

题目描述

给定一个字符串 s ,返回其通过重新排列组合后所有可能的回文字符串,并去除重复的组合。
如不能形成任何回文排列时,则返回一个空列表。

示例 1:
输入: “aabb”
输出: [“abba”, “baab”]

示例 2:
输入: “abc”
输出: []

class Solution {
public:
    vector<string> generatePalindromes(string s){
       
    }
};

题目解析

思路

问题是怎么确保生成的一定是回文串呢?

  • 由于回文串的特性,所以只需要生成前半段字段即可,后面的直接根据前半段得到
  • 又因为回文串可能是奇数/偶数长度:
    • 偶数回文串比如abba,可以平均分成前后半段
    • 奇数回文串比如abcba,需要分成前中后三段
  • 而一个字符串的回文串要存在,那么奇数个的字符只能是0个或者1个,其余的必须是偶数个,所以:
    • 用哈希表来记录所有的字符出现的个数
    • 然后找出出现奇数次的字符加入mid中。如果有两个或者两个以上的奇数个数的字符,那么返回空
    • 对于每个字符,不管其奇偶,都将其个数除以2的个数的字符加入t中,这样做的原因是:
      • 如果是偶数个,将其一半加入t中
      • 如果是奇数,如果有1个,除以2是0,不会有字符加入t,如果是3个,除以2是1,取一个加入t

实现

class Solution {
   void process(std::string &t, int start, const std::string &min, unordered_set<string> & ans){
       if(start >= t.size()){
           ans.insert(t + min + std::string(t.rbegin(), t.rend()));
       }
       for (int i = start; i < t.size(); ++i) {
           if(i != start && t[i] == t[start]){
               continue;
           }
           std::swap(t[i], t[start]);
           process(t, start + 1, min, ans);
           std::swap(t[i], t[start]);
       }
   }
public:
    vector<string> generatePalindromes(string s){
        unordered_set<string> ans;
        unordered_map<char, int > m;
        for(auto ch : s){
            m[ch]++;
        }

        std::string mid, t;
        for(auto it : m){
            if(it.second %2 == 1){
                mid += it.first;
                if(mid.size() > 1){
                    return {};
                }
            }
            t += std::string(it.second / 2, it.first);
        }

        process(t, 0, mid, ans);
        return std::vector<std::string> (ans.begin(), ans.end());
    }
};

实现二

class Solution {
public:
    vector<string> generatePalindromes(string s) {
        vector<string> res;
        unordered_map<char, int> m;
        string t = "", mid = "";
        for (auto a : s) ++m[a];
        for (auto &it : m) {
            if (it.second % 2 == 1) mid += it.first;
            it.second /= 2;
            t += string(it.second, it.first);
            if (mid.size() > 1) return {};
        }
        permute(t, m, mid, "", res);
        return res;
    }
    void permute(string &t, unordered_map<char, int> &m, string mid, string out, vector<string> &res) {
        if (out.size() >= t.size()) {
            res.push_back(out + mid + string(out.rbegin(), out.rend()));
            return;
        } 
        for (auto &it : m) {
            if (it.second > 0) {
                --it.second;
                permute(t, m, mid, out + it.first, res);
                ++it.second;
            }
        }
    }
};

next_permutation

class Solution {
public:
    vector<string> generatePalindromes(string s) {
        vector<string> res;
        unordered_map<char, int> m;
        string t = "", mid = "";
        for (auto a : s) ++m[a];
        for (auto it : m) {
            if (it.second % 2 == 1) mid += it.first;
            t += string(it.second / 2, it.first);
            if (mid.size() > 1) return {};
        }
        sort(t.begin(), t.end());
        do {
            res.push_back(t + mid + string(t.rbegin(), t.rend()));
        } while (next_permutation(t.begin(), t.end()));
        return res;
    }
};
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值