LeetCode005 Longest Palindromic Substring

详细见:leetcode.com/problems/longest-palindromic-substring/

说明: manacher

Java Solution: github

package leetcode;

/*
 * 	假定存在唯一一个最长子序列
 */
public class P005_LongestPalindromicSubstring {
	public static void main(String[] args) {
		System.out.println(new Solution4().longestPalindrome("abad"));
	}
	/*
	 * 	毫无疑问manacher(不会拼错了吧)
	 * 	35.45%
	 * 	特别慢
	 * 	57ms
	 */
	static class Solution {
		private final char sign = '#';
	    public String longestPalindrome(String s) {
	    	if (s == null || s.length() == 0)
	    		return "";
	        char[] m = new char[(s.length() << 1) + 1];
	        for (int i = 0; i != m.length; i ++)
	        	m[i] = (i & 0x1) == 0 ? sign : s.charAt(i >>> 1);
	        int[] r = new int[m.length];
	        r[0] = 0; r[1] = 1;
	        int maxr = 2, core = 1, maxindex = 1;
	        for (int i = 2; i != m.length; i ++) {
	        	if (i >= maxr) {
	        		int newr = 1;
	        		while (i > newr - 1 && i + newr < m.length && m[i + newr] == m[i - newr])
	        			newr ++;
	        		r[i] = newr - 1;
	        		maxr = i + r[i];
	        		core = i;
	        	} else {
	        		int j = (core << 1) - i;
	        		if (r[j] + i < maxr) {
	        			r[i] = r[j];
	        		} else {
	        			int newr = 1;
	        			while (i > newr - 1 && i + newr < m.length && m[i + newr] == m[i - newr])
		        			newr ++;
	        			r[i] = newr - 1;
	        			maxr = i + r[i];
	        			core = i;
	        		}
	        	}
	        	if (r[maxindex] < r[i])
	        		maxindex = i;
	        	if (maxr == m.length)
	        		break;
	        }
	        StringBuilder st = new StringBuilder();
	        for (int i = maxindex - r[maxindex]; i != maxindex + r[maxindex] + 1; i ++)
	        	if ((i & 0x1) == 1)
	        		st.append(m[i]);
	        return st.toString();
	    }
	}
	/*
	 * 	没有使用StringBuilder
	 * 	40.94%
	 * 	43 ms
	 */
	static class Solution2 {
		private final char sign = '#';
	    public String longestPalindrome(String s) {
	    	if (s == null || s.length() == 0)
	    		return "";
	        char[] m = new char[(s.length() << 1) + 1];
	        for (int i = 0; i != m.length; i ++)
	        	m[i] = (i & 0x1) == 0 ? sign : s.charAt(i >>> 1);
	        int[] r = new int[m.length];
	        r[0] = 0; r[1] = 1;
	        int maxr = 2, core = 1, maxindex = 1;
	        for (int i = 2; i != m.length; i ++) {
	        	if (i >= maxr) {
	        		int newr = 1;
	        		while (i > newr - 1 && i + newr < m.length && m[i + newr] == m[i - newr])
	        			newr ++;
	        		r[i] = newr - 1;
	        		maxr = i + r[i];
	        		core = i;
	        	} else {
	        		int j = (core << 1) - i;
	        		if (r[j] + i < maxr) {
	        			r[i] = r[j];
	        		} else {
	        			int newr = 1;
	        			while (i > newr - 1 && i + newr < m.length && m[i + newr] == m[i - newr])
		        			newr ++;
	        			r[i] = newr - 1;
	        			maxr = i + r[i];
	        			core = i;
	        		}
	        	}
	        	if (r[maxindex] < r[i])
	        		maxindex = i;
	        	if (maxr == m.length)
	        		break;
	        }
	        int len = m[maxindex] == sign ?  ( (r[maxindex] + 1) >>> 1 ) << 1 : ( ( r[maxindex] >>> 1) << 1 ) + 1;
	        char[] ans = new char[len];
	        int j = 0;
	        for (int i = maxindex - r[maxindex]; i != maxindex + r[maxindex] + 1; i ++)
	        	if ((i & 0x1) == 1)
	        		ans[j ++] = m[i];
	        return new String(ans);
	    }
	}
	/*
	 * 	不用m char 数组
	 * 	75ms
	 * 	27.05% 
	 */
	static class Solution3 {
		private final char sign = '#';
	    public String longestPalindrome(String s) {
	    	if (s == null || s.length() == 0)
	    		return "";
	        int len = (s.length() << 1) + 1;
	        int[] r = new int[len];
	        r[0] = 0; r[1] = 1;
	        int maxr = 2, core = 1, maxindex = 1;
	        for (int i = 2; i != len; i ++) {
	        	if (i >= maxr) {
	        		int newr = 1;
	        		while (i > newr - 1 && i + newr < len && getIndexOfM(s, i + newr) == getIndexOfM(s, i - newr))
	        			newr ++;
	        		r[i] = newr - 1;
	        		maxr = i + r[i];
	        		core = i;
	        	} else {
	        		int j = (core << 1) - i;
	        		if (r[j] + i < maxr) {
	        			r[i] = r[j];
	        		} else {
	        			int newr = 1;
	        			while (i > newr - 1 && i + newr < len && getIndexOfM(s, i + newr) == getIndexOfM(s, i - newr))
		        			newr ++;
	        			r[i] = newr - 1;
	        			maxr = i + r[i];
	        			core = i;
	        		}
	        	}
	        	if (r[maxindex] < r[i])
	        		maxindex = i;
	        	if (maxr == len)
	        		break;
	        }
	        len = getIndexOfM(s, maxindex) == sign ?  ( (r[maxindex] + 1) >>> 1 ) << 1 : ( ( r[maxindex] >>> 1) << 1 ) + 1;
	        char[] ans = new char[len];
	        int j = 0;
	        for (int i = maxindex - r[maxindex]; i != maxindex + r[maxindex] + 1; i ++)
	        	if ((i & 0x1) == 1)
	        		ans[j ++] = getIndexOfM(s, i);
	        return new String(ans);
	    }
	    char getIndexOfM(String s, int i) {
	    	if ((i & 0x1) == 0)
	    		return sign;
	    	else
	    		return s.charAt(i >>> 1);
	    }
	}
	/*
	 * 	41 ms
	 * 	42.07%
	 */
	static class Solution4 {
		private final char sign = '#';
	    public String longestPalindrome(String s) {
	    	if (s == null || s.length() == 0)
	    		return "";
	        char[] m = new char[(s.length() << 1) + 1];
	        for (int i = 0; i != m.length; i ++)
	        	m[i] = (i & 0x1) == 0 ? sign : s.charAt(i >>> 1);
	        int[] r = new int[m.length];
	        r[0] = 0; r[1] = 1;
	        int maxr = 2, core = 1, maxindex = 1;
	        for (int i = 2; i != m.length; i ++) {
	        	if (i >= maxr) {
	        		int newr = 1;
	        		while (i > newr - 1 && i + newr < m.length && m[i + newr] == m[i - newr])
	        			newr ++;
	        		r[i] = newr - 1;
	        		maxr = i + r[i];
	        		core = i;
	        	} else {
	        		int j = (core << 1) - i;
	        		if (r[j] + i < maxr) {
	        			r[i] = r[j];
	        		} else {
	        			int newr = 1;
	        			while (i > newr - 1 && i + newr < m.length && m[i + newr] == m[i - newr])
		        			newr ++;
	        			r[i] = newr - 1;
	        			maxr = i + r[i];
	        			core = i;
	        		}
	        	}
	        	if (r[maxindex] < r[i])
	        		maxindex = i;
	        	if (maxr == m.length)
	        		break;
	        }
	        return s.substring((maxindex - r[maxindex]) >>> 1, (maxindex + r[maxindex]) >>> 1);
	    }
	}
}


C Solution: github

/*
    url: leetcode.com/problems/longest-palindromic-substring/
    85ms 42.99%
*/



#include <stdlib.h>
#include <stdio.h>
#include <string.h>

char _access_char_array(char* s, int i) {
    if (i % 2 == 0) return '\0';
    return *(s + i / 2);
}

char* longestPalindrome(char* s) {
    int n = strlen(s);
    int ma_n = 2 * n + 1;
    int ma_i = 0;
    int ma_li = 0;
    int ma_mi = 0;
    int ma_mt = 0;
    int l = 0, r = 0, i = 0, j = 0;
    int * ma_r = NULL;
    int ma_an = 0;
    char * answer = NULL;

    //manacher
    ma_r = (int *) malloc(sizeof(int) * ma_n);
    for (ma_i = 0; ma_i < ma_n; ma_i ++)
        *(ma_r + ma_i) = 0;
    for (ma_i = 0; ma_i < ma_n; ma_i ++) {
        if (ma_mt >= ma_n - 1) break;
        ma_mi = 2 * ma_li - ma_i;
        if (ma_i >= ma_mt || (ma_i + *(ma_r + ma_mi) == ma_mt)) {
            l = ma_i;
            r = ma_i;
            while ((l - 1) > -1 && (r + 1) < ma_n && _access_char_array(s, l - 1) == _access_char_array(s, r + 1)) {
                l --;
                r ++;
            }
            *(ma_r + ma_i) = (r - l) / 2;
            ma_an = *(ma_r + ma_an) > *(ma_r + ma_i) ? ma_an : ma_i;
            ma_li = ma_i;
        } else if (ma_i <= ma_mt) {
            *(ma_r + ma_i) = ma_mt - ma_i;
        } else {
            *(ma_r + ma_i) = *(ma_r + ma_mi);
        }
    }
    answer = (char *) malloc(sizeof(char) * (* (ma_r + ma_an) + 1));
    *(answer + *(ma_r + ma_an)) = '\0';
    l = ma_an - *(ma_r + ma_an);
    r = ma_an + *(ma_r + ma_an);
    for (i = l; i <= r; i ++) {
        if (i % 2 == 1)
            *(answer + (j ++)) = _access_char_array(s, i);
    }
    free(ma_r);
    return answer;

}

int main() {
    char* s = "cbbd";
    char* a = longestPalindrome(s);
    unsigned int i = 0;
    printf("len(a) is %d\r\n", strlen(a));
    for (i = 0; i < strlen(a); i ++)
        printf("%c", *(a + i));
    printf("\r\n");
    free(a);
    return 0;
}


Python Solution: github

#coding=utf-8

'''
    url: leetcode.com/problems/longest-palindromic-substring/
    manacher
    @author:     zxwtry
    @email:      zxwtry@qq.com
    @date:       2017年3月26日
    @details:    Solution: AC 632ms 41.14%
'''

class Solution(object):
    def accessString(self, s, index):
        if index % 2 == 0: return '#'
        else: return s[index // 2]
        
    def longestPalindrome(self, s):
        """
        :type s: str
        :rtype: str
        """
        s_len = 0 if s == None else len(s)
        if s_len == 0: return ""
        m = [0] * (2 * s_len + 1)
        m_last_i, m_mirror_r, m_max_touch_i, m_max_r_index = 0, 0, 0, 0
        for i in range(2 * s_len + 1):
            if m_max_touch_i >= 2 * s_len: break
            m_mirror_r = m[2 * m_last_i - i]
            if i >= m_max_touch_i or i + m_mirror_r == m_max_touch_i:
                left, right = i, i
                while left - 1 > -1 and right + 1 < 2 * s_len + 1 and \
                    self.accessString(s, left - 1) == self.accessString(s, right + 1):
                    left, right = (left - 1), (right + 1)
                m[i] = (right - left) // 2
                if m[m_max_r_index] < m[i]:m_max_r_index = i
                m_last_i = i
                m_max_touch_i = right
            elif i + m_mirror_r < m_max_touch_i:
                m[i] = m[2 * m_last_i - i]
            else:
                m[i] = m_max_touch_i - i
        i = m_max_r_index // 2 - m[m_max_r_index] // 2
        return s[i : i + m[m_max_r_index]]

if __name__ == "__main__":
    s1="tabatabag"
    s = Solution()
    print("answer is \"%s\"" % s.longestPalindrome(s1))







评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值