leetcode 回文串

leetcode1177. 构建回文串检测

1. 题目

给你一个字符串s,请你对s的子串进行检测。
每次检测,待检子串都可以表示为queries[i] = [left, right, k]。我们可以重新排列子串s[left], …, s[right],并从中选择 最多 k项替换成任何小写英文字母。
如果在上述检测过程中,子串可以变成回文形式的字符串,那么检测结果为true,否则结果为false。
返回答案数组answer[],其中answer[i]是第i个待检子串queries[i]的检测结果。
注意:在替换时,子串中的每个字母都必须作为 独立的 项进行计数,也就是说,如果s[left…right] = "aaa"且k = 2,我们只能替换其中的两个字母。(另外,任何检测都不会修改原始字符串 s,可以认为每次检测都是独立的)

示例:
输入:s = “abcda”, queries = [[3,3,0],[1,2,0],[0,3,1],[0,3,2],[0,4,1]]
输出:[true,false,false,true,true]
解释:
queries[0] : 子串 = “d”,回文。
queries[1] :子串 = “bc”,不是回文。
queries[2] :子串 = “abcd”,只替换 1 个字符是变不成回文串的。
queries[3] :子串 = “abcd”,可以变成回文的 “abba”。 也可以变成 “baab”,先重新排序变成 “bacd”,然后把 “cd” 替换为 “ab”。
queries[4] :子串 = “abcda”,可以变成回文的 “abcba”。

2. 解答

/*
注意题目的要求:1、子串重新排列2、任意修改k次以内。
因此只要统计,left到right区间内每个字符出现的次数。
*/

int** Compute(char* s, int size, int** hash)
{
    for (int i = 1; i <= size; i++) {
        for (int j = 0; j < 26; j++) {
            hash[i][j] = hash[i - 1][j];
        }
        hash[i][s[i - 1] - 'a']++;
    }
    return hash;
}
bool Query(char* s, int left, int right, int k, int** hash)
{
    int i;
    int count = 0;
    for (int i = 0; i < 26; i++) {
        if ((hash[right + 1][i] - hash[left][i]) % 2 == 1) {
            count++;
        }
    }
    count = count / 2;
    if (count > k) {
        return false;
    }
    return true;
}
bool* canMakePaliQueries(char* s, int** queries, int queriesSize, int* queriesColSize, int* returnSize)
{
    *returnSize = queriesSize;

    int size = strlen(s);
    int** hash = (int**)malloc(sizeof(int*) * (size + 1));
    for (int i = 0; i <= size; i++) {
        hash[i] = (int*)malloc(26 * sizeof(int));
        memset(hash[i], 0, sizeof(int) * 26);
    }
    hash = Compute(s, size, hash);
    bool* ans = (bool*)malloc(sizeof(bool) * queriesSize);
    for (int i = 0; i < queriesSize; i++) {
        bool flag = Query(s, queries[i][0], queries[i][1], queries[i][2], hash);
        ans[i] = flag;
    }
    return ans;
}

leetcode5. 最长回文子串

1. 题目

给你一个字符串 s,找到 s 中最长的回文子串。

示例 1:
输入:s = “babad”
输出:“bab”
解释:“aba” 同样是符合题意的答案。

示例 2:
输入:s = “cbbd”
输出:“bb”

示例 3:
输入:s = “a”
输出:“a”

示例 4:
输入:s = “ac”
输出:“a”

2. 解答

回文串:如果一个字符串正着读和反着读都是一样的,就是回文串

中心扩展算法:
我们观察到回文中心的两侧互为镜像。因此,回文可以从它的中心展开,并且只有2n-1个这样的中心。
你可能会问,为什么会是 2n - 1 个,而不是 n 个中心?
因为回文的中心要区分单双。

  • 假如回文的中心为双数,例如 abba,那么可以划分为 ab bb ba,对于n长度的字符串,这样的划分有 n-1 种。

  • 假为回文的中心为单数,例如 abcd, 那么可以划分为 a b c d, 对于n长度的字符串,这样的划分有 n 种。

对于 n 长度的字符串,我们其实不知道它的回文串中心倒底是单数还是双数,所以我们要对这两种情况都做遍历,也就是 n+(n-1) = 2n - 1,所以时间复杂度为 O(n)。

当中心确定后,我们要围绕这个中心来扩展回文,那么最长的回文可能是整个字符串,所以时间复杂度为 O(n)。

所以总时间复杂度为 O(n^2)

// 中心扩展法

#define MAX(a, b) (((a) > (b)) ? (a) :(b))

int expandAroundCenter(char *s, int len, int left, int right) {
    int l = left;
    int r = right;
    while (l >= 0 && r < len && s[l] == s[r]) {
        // 计算以left和right为中心的回文串长度
        l--;
        r++;
    }
    return r - l - 1;
}

char * longestPalindrome(char * s) {
    int len = strlen(s);
    if (len <= 1) {
        return s;
    }

    int start = 0;
    int end = 0;
    int maxLen = 0;
    

    for (int i = 0; i < len; i++) {
        int len1 = expandAroundCenter(s, len, i, i);    // 一个元素为中心
        int len2 = expandAroundCenter(s, len, i, i + 1);   // 两个元素为中心
        maxLen = MAX(MAX(len1, len2), maxLen);
        if (maxLen > end - start + 1) {
            start = i - (maxLen - 1) / 2;   // 获取回文串起始点位置
            end = i + maxLen / 2;    // 获取回文串结束点位置        
		}
    }
    int index = 0;
    char *res = (char *)malloc(sizeof(char) * (maxLen + 1));
    for (int i = start; i < start + maxLen; i++) {
        res[index++] = s[i];
    }
    res[index] = '\0';
    return res;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值