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;
    }

你可能感兴趣的:(leetcode)