LeetCode刷题笔记——回文子串

LeetCode刷题笔记——回文素数

1. 什么是回文子串?

所谓回文串就是从前面读和从后面读完全一样的字符串。根据字符数量分为两类:
-奇数个:中间数字只有一个 aba
-偶数个:中间数字有两个 abba

2. 如何查找回文子串?

这个函数的前提是l和r满足这样的关系:
l==r 或者r=l+1

string palindrome(string &s, int l, int r){
	while(l>=0&&r<s.size()&&s[l]==s[r]){
		l--;
		r++;
	}
	return str.substr(l+1,r-l-1);
}

3. 回文子串枚举方法

方法一:从中心往两侧延伸【通过】

思路
在长度为 N 的字符串中,可能的回文串中心位置有 2N-1 个:字母,或两个字母中间。
从每一个回文串中心开始统计回文串数量。回文区间 [a, b] 表示 S[a], S[a+1], …, S[b] 是回文串,根据回文串定义可知 [a+1, b-1] 也是回文区间。
算法
对于每个可能的回文串中心位置,尽可能扩大它的回文区间 [left, right]。当 left >= 0 and right < N and S[left] == S[right] 时,扩大区间。此时回文区间表示的回文串为 S[left], S[left+1], …, S[right]。
代码:

for(int i=0;i<2*n-1;i++){
	int left=i/2;
	int right=i%2;
}

通过以上代码就枚举了所有的中心元素情况。包含一个中心和两个中心的情况。然后扩展即可。

马拉车算法

思路
马拉车算法可以在线性时间内找出以任何位置为中心的最大回文串。
算法
假设一个回文串中心为 center,该中心对应的最大回文串右边界为 right。存在一个 i 为当前回文串中心,满足 i > center,那么也存在一个 j 与 i 关于 center 对称,可以根据 Z[i] 快速计算出 Z[j]。

当 i < right 时,找出 i 关于 center 的对称点 j = 2 * center - i。此时以 i 为中心,半径为 right - i 的区间内存在的最大回文串的半径 Z[i] 等于 Z[j]。

例如,对于字符串 A = ‘@#A#B#A#A#B#A#$’,当 center = 7, right = 13, i = 10 时,center 为两个字母 A 中间的 #,最大回文串右边界为最后一个 #,i 是最后一个 B,j 是第一个 B。

在 [center - (right - center), right] 中,区间中心为 center,右边界为 right,i 和 j 关于 center 对称,且 Z[j] = 3,可以快速计算出 Z[i] = min(right - i, Z[j]) = 3。

在 while 循环中,只有当 Z[i] 超过 right - i 时,才需要逐个比较字符。这种情况下,Z[i] 每增加 1,right 也会增加 1,且最多能够增加 2*N+2 次。因此这个过程是线性的。

最后,对 Z 中每一项 v 计算 (v+1) / 2,然后求和。假设给定最大回文串中心为 C,半径为 R,那么以 C 为中心,半径为 R-1, R-2, …, 0 的子串也都是回文串。例如 abcdedcba 是以 e 为中心,半径为 4 的回文串,那么 e,ded,cdedc,bcdedcb 和 abcdedcba 也都是回文串。

除以 2 是因为实际回文串的半径为 v 的一半。例如回文串 a#b#c#d#e#d#c#b#a 的半径为实际原回文串半径的 2 倍。

def countSubstrings(self, S):
    def manachers(S):
        A = '@#' + '#'.join(S) + '#$'
        Z = [0] * len(A)
        center = right = 0
        for i in xrange(1, len(A) - 1):
            if i < right:
                Z[i] = min(right - i, Z[2 * center - i])
            while A[i + Z[i] + 1] == A[i - Z[i] - 1]:
                Z[i] += 1
            if i + Z[i] > right:
                center, right = i, i + Z[i]
        return Z

    return sum((v+1)/2 for v in manachers(S))

4. 回文链表判断

对链表后半部分进行翻转。然后顺序比较即可。翻转可以在原地操作。
**思路:**快慢指针找到链表的中间元素。根据fast是否为空确定链表长度是奇数还是偶数。如果是奇数,slow还得往后移动一个。
然后对slow开始的链表进行翻转。

翻转链表

ListNode* reverse(ListNode *node){
        ListNode *pre=NULL,*cur=node;
        while(cur){
            ListNode *next=cur->next;
            cur->next=pre;
            pre=cur;
            cur=next;
        }
        return pre;
    }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
根据提供的引用内容,有三种方法可以解决LeetCode上的最长文子串。 方法一是使用扩展中心法优化,即从左向右遍历字符串,找到连续相同字符组成的子串作为扩展中心,然后从该中心向左右扩展,找到最长的文子串。这个方法的时间复杂度为O(n²)。\[1\] 方法二是直接循环字符串,判断子串是否是文子串,然后得到最长文子串。这个方法的时间复杂度为O(n³),效率较低。\[2\] 方法三是双层for循环遍历所有子串可能,然后再对比是否反向和正向是一样的。这个方法的时间复杂度也为O(n³),效率较低。\[3\] 综上所述,方法一是解决LeetCode最长文子串的最优解法。 #### 引用[.reference_title] - *1* [LeetCode_5_最长文子串](https://blog.csdn.net/qq_38975553/article/details/109222153)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insertT0,239^v3^insert_chatgpt"}} ] [.reference_item] - *2* [Leetcode-最长文子串](https://blog.csdn.net/duffon_ze/article/details/86691293)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insertT0,239^v3^insert_chatgpt"}} ] [.reference_item] - *3* [LeetCode 第5:最长文子串(Python3解法)](https://blog.csdn.net/weixin_43490422/article/details/126479629)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insertT0,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值