【每日一题】对称之美 && 非对称之美

对称之美:

已截全。
在这里插入图片描述

思路一(究极暴力):

第一眼我想到的是dfs + check。
先进行全排列一遍,每次排列的到的结果进行一次回文判断。
因为我觉得数据量很小,虽然这个解法时间复杂度很高,不过应该是能过。

但结果不尽如人意。

关于dfs的具体思路可以画一个决策树:这样我们分析一个具体的节点即可。
还要注意一些回溯与剪枝的细节,虽然注意了也还是时间复杂度太高了就是了。
在这里插入图片描述

代码:

#include <iostream>
#include <vector>

using namespace std;

bool flag = false;
string ret;

void check(string& str)
{
    int left = 0, right = str.size() - 1;
    while (left < right)
    {
        if (str[left] == str[right])
        {
            left++;
            right--;
        }
        else
        {
            break;
        }
    }
    if (left == right || left == right + 1) flag = true;
}

void dfs(vector<string>& vs, int i)
{
    if (i == vs.size() || flag == true) return;
    for (auto& val : vs[i])
    {
        ret.push_back(val);
        if (ret.size() == vs.size()) check(ret);
        dfs(vs, i + 1);
        ret.pop_back();
    }
}

int main()
{
    int t;
    cin >> t;
    while (t--)
    {
        int n, i = 0;
        flag = false;
        cin >> n;
        vector<string> vs(n);
        for (int j = 0; j < n; j++) cin >> vs[j];

        dfs(vs, i);

        if (flag) cout << "Yes" << endl;
        else cout << "No" << endl;
    }

    return 0;
}

思路二(双指针+哈希):

这是一个很棒的解法:
我们判断一个字符串是否为回文时,可以利用双指针逐步缩小区间。
在这里插入图片描述
将这个解法延伸一下,即使每个是字符串也可以。
为什么?
因为我们将当前left与right对应的字符串进行check是否有相同字符即可。

进行check的策略有二:
其一是进行暴力,也就是两种for循环枚举。
其二是Hash优化。

代码:

#include <iostream>
#include <vector>
#include <string>

using namespace std;

bool check(string& str1, string str2)
{
    bool hash1[26] = { false }, hash2[26] = { false };
    for (auto& ch : str1) hash1[ch - 'a'] = true;
    for (auto& ch : str2) hash2[ch - 'a'] = true;

    for (int i = 0; i < 26; i++)
    {
        if (hash1[i] == true && hash2[i] == true)
        {
            return true;
        }
    }
    return false;
}

int main()
{
    int t;
    cin >> t;
    while (t--)
    {
        int n, i = 0;
        cin >> n;
        vector<string> vs(n);
        for (int j = 0; j < n; j++) cin >> vs[j];

        int left = 0, right = n - 1;
        while (left < right)
        {
            if (check(vs[left], vs[right]))
            {
                left++;
                right--;
            }
            else
            {
                break;
            }
        }
        if (left == right || left == right + 1) cout << "Yes" << endl;
        else cout << "No" << endl;
    }

    return 0;
}

非对称之美:

在这里插入图片描述

一些错误思路:

对于一些解决回文字符串的常规思路去套是解决不出来的,
比如中心扩展,dp,纯暴力,博主都试过一次,这题的思路更倾向于一个脑筋急转弯?

贪心/规律:

真正的解法很简单

  1. 判断当前整个字符串是否为回文串,不是的话直接返回当前字符串长度即可。
  2. 是回文的话我们直接减1即可。
    在这里插入图片描述
  3. 对于二来说有一个特例:当整个字符串全部为同一个字母时,需要输出0,因为左边或者右边删掉一个仍旧是回文串。

找到规律就直接变成一个纯纯的代码题了

代码:

#include <iostream>
#include <string>

using namespace std;

int main()
{
    string str;
    cin >> str;
    // 进行特殊判断,若是当前字符串为全重复字符那么flag为true。
    bool flag = true;
    for (int i = 1; i < str.size(); i++)
    {
        if (str[0] != str[i])
        {
            flag = false;
            break;
        }
    }
    if (flag) 
    {
        cout << 0;
        return 0;
    }
    // 判断当前字符串是否为回文
    int left = 0, right = str.size() - 1;
    while (left < right)
    {
        if (str[left] == str[right])
        {
            left++;
            right--;
        }
        else
        {
            break;
        }
    }
    if (left == right || left == right + 1) cout << str.size() - 1;
    else cout << str.size();
    
    return 0;
}

完~

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值