1.最长回文串
/*
* 计算一组字符集合可以组成的回文字符串的最大长度
* */
public int longestPalindrome(String s) {
if (s == null || s.length() == 0) return 0;
int sMap[] = new int[128];
for (int i = 0; i < s.length(); i++) {
sMap[s.charAt(i)]++;
}
int tmp = 0;
int count = 0;
for (int i = 0; i < sMap.length; i++) {
if (sMap[i] % 2 == 1) tmp = 1;
count += sMap[i] / 2;
}
return count * 2 + tmp;
}
@Test
public void test() {
System.out.println(longestPalindrome("abccccdd"));
}
2.同构字符串
/*
* 同构字符串
* 给定两个字符串 s 和 t,判断它们是否是同构的。如果 s 中的字符可以被替换得到 t ,那么这两个字符串是同构的。
* 所有出现的字符都必须用另一个字符替换,同时保留字符的顺序。两个字符不能映射到同一个字符上,但字符可以映射自己本身。
* */
public boolean isIsomorphic(String s, String t) {//做法一
if (s == null || t == null || s.length() != t.length()) return false;
Map<Character, Character> st = new HashMap<>();
Map<Character, Character> ts = new HashMap<>();
int len = s.length();
for (int i = 0; i < len; i++) {
if (st.containsKey(s.charAt(i))) {
if (st.get(s.charAt(i)) != t.charAt(i)) return false;
} else if (ts.containsKey(t.charAt(i))) {
if (ts.get(t.charAt(i)) != s.charAt(i)) return false;
} else {
st.put(s.charAt(i), t.charAt(i));
ts.put(t.charAt(i), s.charAt(i));
}
}
return true;
}
public boolean isIsomorphic2(String s, String t) {//做法二
return isIsomorphicHelper(s, t) && isIsomorphicHelper(t, s);
}
public boolean isIsomorphicHelper(String str1, String str2) {//验证str1可以被唯一的映射到str2
HashMap<Character, Character> map = new HashMap<>();//s->t
for (int i = 0; i < str1.length(); i++) {
char c1 = str1.charAt(i);
char c2 = str2.charAt(i);
if (map.containsKey(c1)) {
if (map.get(c1) != c2) {
return false;
}
} else {
map.put(c1, c2);
}
}
return true;
}
3.回文子串的个数
/*
* 回文子字符串个数
* 给定一个字符串,你的任务是计算这个字符串中有多少个回文子串。具有不同开始位置或结束位置的子串,即使是由相同的字符组成,也会被计为是不同的子串。
* */
//回文子串的个数
public int countSubstrings(String s) {
if (s == null || s.length() == 0) return 0;
int n = s.length();
boolean dp[][] = new boolean[n][n];//dp[i][j]表示i~j之间是否为回文串
int count = 0;
for (int len = 0; len < n; len++) {
for (int i = 0; i < n - len; i++) {
int j = i + len;
if (s.charAt(i) == s.charAt(j) && (j - i <= 1)) {
dp[i][j] = true;
count++;
} else if (s.charAt(i) == s.charAt(j) && dp[i + 1][j - 1]) {
dp[i][j] = true;
count++;
}
}
}
return count;
}
4.回文数判断
力扣传送门
判断一个整数是否是回文数。回文数是指正序(从左向右)和倒序(从右向左)读都是一样的整数。
/*
* 回文数
* 判断一个整数是否是回文数。回文数是指正序(从左向右)和倒序(从右向左)读都是一样的整数。
* 要求:不将整数转为字符串
* 思路:例如,输入 1221,我们可以将数字 “1221” 的后半部分从 “21” 反转为 “12”,并将其与前半部分 “12” 进行比较,因为二者相同,我们得知数字 1221 是回文。
* 要注意10这种情况
* */
public boolean isPalindrome(int x) {
if (x < 0) return false;//负数直接返回false
if (x == 0) return true;//是0返回true
if (x % 10 == 0) return false;//注意这个条件。因为后面判断x == x2 / 10时,会把10,110错误返回为true
int x2 = 0;
while (x > x2) {
int num = x % 10;
x = x / 10;
x2 = x2 * 10 + num;
}
return x == x2 || x == x2 / 10;
}
@Test
public void test2() {
System.out.println(isPalindrome(110));
}
5.计数二进制子串
力扣传送门
统计二进制字符串中连续 1 和连续 0 数量相同的子字符串个数
/*
* 计数二进制子串:统计二进制字符串中连续 1 和连续 0 数量相同的子字符串个数
* 给定一个字符串 s,计算具有相同数量0和1的非空(连续)子字符串的数量,并且这些子字符串中的所有0和所有1都是组合在一起的。重复出现的子串要计算它们出现的次数。
* */
public int countBinarySubstrings(String s) {//方法一:动态规划O(N^2)超时
if (s == null || s.length() == 0) return 0;
int n = s.length();
int count = 0;
boolean dp[][] = new boolean[n + 1][n + 1];//i~j之间是否为 符合条件的子串
for (int j = 0; j < n; j++) {
for (int i = j - 1; i >= 0; i--) {
if (s.charAt(i) != s.charAt(j)) {
if ((j - i == 1) || (dp[i + 1][j - 1] && s.charAt(i) == s.charAt(i + 1) && s.charAt(j) == s.charAt(j - 1))) {
dp[i][j] = true;
count++;
}
}
}
}
return count;
}
public int countBinarySubstrings2(String s) {//方法一:先分块,连续的1或0被分到一块,再统计 O(N)
if (s == null || s.length() == 0) return 0;
int batch[] = new int[s.length()];
int count = 0;
batch[count] = 1;
for (int i = 1; i < s.length(); i++) {
if (s.charAt(i) == s.charAt(i - 1)) {
batch[count]++;
} else {
count++;
batch[count] = 1;
}
}
int cnt = 0;
for (int i = 0; i < count; i++) {
cnt += Math.min(batch[i], batch[i + 1]);
}
return cnt;
}
@Test
public void test3() {
System.out.println(countBinarySubstrings2("10101"));
}