409. 最长回文串

题目描述

给定一个包含大写字母和小写字母的字符串 s ,返回 通过这些字母构造成的 最长的回文串 。

在构造过程中,请注意 区分大小写 。比如 "Aa" 不能当做一个回文字符串

 示例 1:

输入:s = "abccccdd"
输出:7
解释:
我们可以构造的最长的回文串是"dccaccd", 它的长度是 7。

 示例 2:

输入:s = "a"
输出:1

  示例 3:

输入:s = "aaaaaccc" 
输出:7

 提示:

  • 1 <= s.length <= 2000
  • s 只由小写 和/或 大写英文字母组成

 法一:由回文字符串的特点可以得出:在一个回文串中,最多只有一个字符出现了奇数次,其余字符都出现了偶数次,且它们可以看作是首尾呼应的,即呈中心对称。如下图所示:

       根据这一特点,我们可以先统计给定的字符串中每个字符出现的次数。若为偶数次,那就两两一组分别放置在中心对称线的左右两侧的相应对称位置处;若为奇数次,那么如果按照偶数次的方式进行处理的话,最终会多出一个字符,多出来的字符先放着不管。

       具体描述为:对于一个字符 c , 如果它在给定的字符串中出现了 m 次,那么我们就可以使用 m / 2 * 2次,即在回文串的左右两侧各放置 m / 2 个。 对于那些出现了奇数次的字符,我们最终只能添加一个到回文串中作为回文中心。

class Solution {
    public int longestPalindrome(String s) {
         
        int result = 0;      //用于统计最长回文串的长度

        int[] counts = new int[123];   // 'z'对应的ASCII码值为122

        int length = s.length();

        for(int i = 0; i < length; i++){
            char c = s.charAt(i);
            counts[c]++;
        } 

        for(int i : counts){
           result += i /2 * 2;
           if(i % 2 == 1 && result % 2 == 0){
               result++;
           }
        }
        return result;
    }
}

     在上述代码段中,首先声明了一个长度为123的整型数组,用于存储给定字符串中各个字符出现的次数。其中在赋值时下标是用字符表示的,所以存在一个自动类型提升的过程;此外,长度设置为123是因为小写字母 'z' 对应的ASCII码值为122,那么122就是数组counts的最大下标,所以数组的长度设置为123就可以正好满足条件。大小写英文字母所对应的ASCII码值如下表格中所示:

大写字母

十进制ASCII

小写字母

十进制ASCII

A

65

a

97

B

66

b

98

C

67

c

99

D

68

d

100

E

69

e

101

F

70

f

102

G

71

g

103

H

72

h

104

I

73

i

105

J

74

j

106

K

75

k

107

L

76

l

108

M

77

m

109

N

78

n

110

O

79

o

111

P

80

p

112

Q

81

q

113

R

82

r

114

S

83

s

115

T

84

t

116

U

85

u

117

V

86

v

118

W

87

w

119

X

88

x

120

Y

89

y

121

Z

90

z

122

     第一个for循环的作用就是遍历字符串 s 中的每一个字符,并记录出各个字符出现的次数。在第二个for循环当中,其实就是对数组counts中元素值的累加操作,在出现元素值为偶数时就直接累加;如果是出现奇数,则只累加 当前元素值 - 1 , 同时为了确保构成的回文串中只能有一个回文中心,在遇到元素值为奇数时需判断当前的 result 的值是否为偶数,若是就说明到目前为止并没有为回文串添加回文中心字符(即在之前遍历的counts的元素值都为偶数),可以给result自增1;若result的值不是偶数,则说明在此之前已经遍历到元素值为奇数的字符并且已经为回文串添加了回文中心字符串(即 result 的值已经自增过了),而前面的描述已经给出了 result 的值只会自增一次,所以就跳过不再处理。

      最后提一下数组元素的默认初始化值问题。在我们所维护的长度为123的整型数组中,至少有(123 - 2 * 26)个元素值没有填充过值,那么默认的初始化值为零。这是因为:

数组是引用数据类型,它的元素相当于类的成员变量,所以数组元素是有默认值的。数组一经分配,其中的每个元素也被按照成员变量同样的方式被隐式初始化。

 不同类型元素的默认初始值如下:

数组元素类型

元素默认初始值

byte

0

short

0

int

0

long

0L

float

0.0F

double

0.0

char

0或写为’\u0000’

boolean

false

引用类型

null

 法二:使用HashSet存储给定字符串中的字符。

        思路如下:根据HashSet中存储元素不能重复的特点,依次遍历字符串中的每个字符,遇到新的字符就添加到HashSet的对象 set 中,之后第二次遇到该字符就从set中清除,第三次遇到后再添加进去,第四次遇到就再清除,......, 对于每个字符都如此循环往复处理。那么到最后 set 中遗留的字符就是给定字符串中出现次数为奇数的字符,记字符串的长度为 n, set 的长度为m, 那么当 m=0 时,回文串的长度就是给定字符串的长度 n , 此时回文串长度为偶数;若 m > 0, 表明给定字符串中存在出现次数为奇数的字符,但是我们只能为偶数长度的回文串添加一个回文中心字符,所以回文串的长度为:n - m + 1 。

class Solution {
    public int longestPalindrome(String s) {
         
        int result = 0;
        Set<Character> set = new HashSet<>();
        for(int i=0;i < s.length();i++){
            char c = s.charAt(i);
            if(!set.remove(c)){
                set.add(c);
            }
        }
        return set.size()==0 ? s.length() : s.length()-set.size() + 1;
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值