1. 程式人生 > >LeetCode第五題:最長迴文子串(C語言)

LeetCode第五題:最長迴文子串(C語言)

給定一個字串 s,找到 s 中最長的迴文子串。你可以假設 s 的最大長度為1000。

示例 1:

輸入: “babad” 輸出: “bab” 注意: "aba"也是一個有效答案。 示例 2:

輸入: “cbbd” 輸出: “bb”

解法一:暴力求解法

思想: 反轉 S,使之變成 S’。找到 S 和 S’之間最長的公共子串,這也必然是最長的迴文子串。 理由:如果找兩個字串的公共子串,i指向第一個字串,j指向第二個字串,用暴力求解法肯定就是i每走一步,j就不斷的從頭遍歷第二個字串,然後判斷是否相等。 j從前往後走,就相當於原字串從後向前走。 S=“abacdfgdcaba” , S ′ =“abacdgfdcaba”:S 以及 S’ 之間的最長公共子串為 “abacd”,顯然,這不是迴文。所以我們要加一個判斷條件就可以了。 暴力演算法的時間複雜度為O(n^3),在LeetCode中跑步過去,僅供參考

	//判斷一個字串是不是迴文
	int IfPlalindrome(char *s) {
		int count = strlen(s);
		int left = 0;
		int right = count - 1;
		while (left < right)
		{
			if (s[left] != s[right])
			{
				return 0; //不是迴文返回0,是迴文返回1
			}
			left++;
			right--;
		}
		return 1;
	}
	//反轉字串
	char *reverse(char *s, int count)
	{
		char *p = (char *)malloc(sizeof(char) * (count + 1));
		int i = 0;
		for (; i < count; i++)
		{
			p[i] = s[count - i - 1];
		}
		p[i] = '\0';
		return p;
	}
	
	char* longestPalindrome(char* s) {
		int count = strlen(s);
		//arr中存放的是最長的迴文子串
		char *arr = (char *)malloc(sizeof(char) * 1001);
		char *p = reverse(s, count);
		unsigned int max = 0;
		//arr1中存放每一次迴圈遇見的迴文子串
		char arr1[2000];
		for (int i = 0; i < count; i++) {
			for (int j = 0; j < count; j++) {
				int m = i;
				int n = j;
				int k = 0;
				while (s[m] == p[n])
				{
					arr1[k] = s[m];
					k++;
					m++;
					n++;
				}
				arr1[k] = '\0';
				//判斷是不是迴文子串
				if (IfPlalindrome(arr1))
				{
					//和arr中的迴文子串長度作對比,大的話,就更新
					if (strlen(arr1) > max)
					{
						max = strlen(arr1);
						strcpy(arr, arr1);
					}
				}
			}
		}
		return arr;
	}

解法二:動態規劃

在暴力求解法中,判斷子串用了很多重複的操作,動態規劃就是要儘量避免重複的操作。 s的長度為N,生成一個N*N的二維陣列dp[1001][1001]

  • dp[i][j] 表示從s[i]到s[j]是否是迴文
  • dp[i][i] = true 因為dp[i][i]一定是迴文
  • 在動態規劃中只需要記錄迴文開始的位置和長度即可 時間複雜度:O(n^2) 空間複雜度:O(N^2)
    char* longestPalindrome(char* s)
   {
   	int len = strlen(s);
   	if (len <= 1) { return s; }
   	//定義bool型別的dp,只能為true或false
   	bool dp[1001][1001];
   	memset(dp, 0, sizeof(dp));
   	dp[0][0] = 1;
   	for (int i = 1; i < len; i++)
   	{
   		dp[i][i] = true;
   		//一定不要忽略,在下面k=2會用到
   		dp[i][i - 1] = true;
   	}
   	int left = 0;
   	int right = 0;
   	int max = 0;
   	//k表示迴文子串的長度
   	for (int k = 2; k <= len; k++)
   	{
   		//i表示迴文子串的起始位置
   		for (int i = 0; i < len - k + 1; i++)
   		{
   			if (s[i] == s[k - 1 + i] && dp[i + 1][k + i - 2])
   			{
   				dp[i][k - 1 + i] = true;
   				if (max < k - 1)
   				{
   					max = k - 1;
   					left = i;
   					right = k - 1 + i;
   				}
   			}
   		}
   	}
   
   	char *arr = (char *)malloc(sizeof(int) * (max * 2));
   	int i = 0;
   	for (; i <= max; i++)
   	{
   		arr[i] = s[left++];
   	}
   	arr[i] = '\0';
   	return arr;
   }

解法三:中心擴充套件法

以某個元素為中心,分別計算偶數長度的迴文最大長度和奇數長度的迴文最大長度。 時間複雜度O(N^2)

	char* longestPalindrome(char* s)
	{
		int len = strlen(s);
		if (len <= 1) { return s; }
		int start = 0;
		int maxlen = 0;
		//i表示中間元素下標
		for (int i = 1; i < len; i++)
		{
			//偶數長度
			int low = i - 1;
			int high = i;
			while (low >= 0 && high < len && s[low] == s[high])
			{
				low--;
				high++;
			}
			if (high - low - 1 > maxlen)
			{
				maxlen = high - low - 1;
				start = low + 1;
			}
			//奇數長度
			low = i - 1; high = i + 1;
			while (low >= 0 && high < len && s[low] == s[high])
			{
				low--;
				high++;
			}
			if (high - low - 1 > maxlen)
			{
				maxlen = high - low - 1;
				start = low + 1;
			}
		}
		char *arr = (char *)malloc(sizeof(int) * (maxlen * 2));
		int i = 0;
		for (; i < maxlen; i++)
		{
			arr[i] = s[start++];
		}
		arr[i] = '\0';
		return arr;
	}