問題:
Given a string which consists of lowercase or uppercase letters, find the length of the longest palindromes that can be built with those letters.
This is case sensitive, for example "Aa" is not considered a palindrome here.
Note:
Assume the length of given string will not exceed 1,010.
Example:Input:
"abccccdd"
Output:
7
Explanation:
One longest palindrome that can be built is "dccaccd", whose length is 7.
大意:
給出一個由小寫或大寫字母組成的字符串,找到能被其中的字母組成的最長的回文的長度。
這是區分大小寫的,比如“Aa”就不能認為是回文。
注意:
假設給出的字符串長度不會超過1010。
例子:輸入:
“abccccdd”
輸出:
7
解釋:
最長的回文為“dccaccd”,長度為7。
思路:
這里回文的意思就是正著和反著都是一樣的字母順序。思路大家都是比較一致的,先看看字符串有哪些字母以及各自的數量,把成雙成對的數量的字母都挑出來,取其能成雙的最大數量,這樣可以對稱地放在回文的兩邊,然后看有沒有落單的字母或者在成雙后還有剩余一個的字母,有就放在回文最中間,這樣就是最長的回文了,數量也就出來了。這里是區分大小寫的,所以要分開算。不過題目中的1010這個最長字符串長度沒發現有什么特別的用處。
代碼(Java):
public class Solution {
public int longestPalindrome(String s) {
int[] letterNum = new int[26*2];
char[] sArray = s.toCharArray();
for (int i = 0; i < sArray.length; i++) {
if ((sArray[i] - 'a') >= 0) {// 小寫字母
letterNum[(sArray[i] - 'a')]++;
} else {// 大寫字母
letterNum[(sArray[i] - 'A' + 26)]++;
}
}
int result = 0;
boolean hasSingle = false;// 有無單個字符的標記
boolean hasOdd = false;// 有無2個以上奇數數量字符的標記
for (int i = 0; i < 26*2; i++) {
if (letterNum[i] > 0 && letterNum[i] < 2) hasSingle = true;
if (letterNum[i] > 1) {
result += letterNum[i] / 2 * 2;
if (letterNum[i] % 2 == 1) hasOdd = true;
}
}
result += hasSingle || hasOdd ? 1 : 0;
return result;
}
}
他山之石:
public int longestPalindrome(String s) {
boolean[] map = new boolean[128];
int len = 0;
for (char c : s.toCharArray()) {
map[c] = !map[c]; // flip on each occurrence, false when seen n*2 times
if (!map[c]) len+=2;
}
if (len < s.length()) len++; // if more than len, atleast one single is present
return len;
}
這個做法其實思路是一樣的,只是更加精簡巧妙,boolan數組初始化時都是false,128的長度是為了包含所有ASCII碼,懶得特意去判斷大小寫了,每次遇到一個字母就將其對應的位置取反,如果出現兩次就會又變回false,那么每出現兩次就可以將回文長度加2。最后看加起來的長度和原字符串長度是否相同,不同則說明有單個字符剩余,就可以放在回文正中間,跟我的做法比,思路差不多,代碼卻巧妙多了,厲害呀。
合集:https://github.com/Cloudox/LeetCode-Record