14:字符串中的变位词

:::info 题目:输入字符串s1和s2,如何判断字符串s2中是否包含字符串s1的某个变位词?如果字符串s2中包含字符串s1的某个变位词,则字符串s1至少有一个变位词是字符串s2的子字符串。假设两个字符串中只包含英文小写字母。例如,字符串s1为”ac”,字符串s2为”dgcaf”,由于字符串s2中包含字符串s1的变位词”ca”,因此输出为true。如果字符串s1为”ab”,字符串s2为”dgcaf”,则输出为false。 :::

  1. public class CheckInclusion {
  2. public static boolean checkInclusion(String s1, String s2) {
  3. if (s2.length() < s1.length()) {
  4. return false;
  5. }
  6. int[] countTable = new int[26];
  7. for (int i = 0; i < s1.length(); i++) {
  8. // 先统计s1中字符的数量
  9. countTable[s1.charAt(i) - 'a']++;
  10. // 借这个循环同时统计s2的前s1.length()的字符
  11. countTable[s2.charAt(i) - 'a']--;
  12. }
  13. if (checkAllZero(countTable)) {
  14. return true;
  15. }
  16. // 双指针走s2的后半段
  17. for (int i = s1.length(); i < s2.length(); i++) {
  18. // 右指针挪一位,相当于纳入当前的子字符串的统计范围,减去1
  19. countTable[s2.charAt(i) - 'a']--;
  20. // 左指针挪一位,相当于被剔除当前的字符串的统计范围,加回1
  21. countTable[s2.charAt(i - s1.length()) - 'a']++;
  22. if (checkAllZero(countTable)) {
  23. return true;
  24. }
  25. }
  26. return false;
  27. }
  28. private static boolean checkAllZero(int[] countTable) {
  29. for (int count : countTable) {
  30. if (count != 0) {
  31. return false;
  32. }
  33. }
  34. return true;
  35. }
  36. public static void main(String[] args) {
  37. System.out.println(checkInclusion("ac", "bcade"));
  38. System.out.println(checkInclusion("ec", "bcade"));
  39. }
  40. }

16:不含重复字符的最长子字符串

:::info 题目:输入一个字符串,求该字符串中不含重复字符的最长子字符串的长度。例如,输入字符串”babcca”,其最长的不含重复字符的子字符串是”abc”,长度为3。 :::

  1. public class CheckLongestSubString16 {
  2. public static int findLongestSubString(String str) {
  3. if (str.length() == 0) {
  4. return 0;
  5. }
  6. int maxLength = 1;
  7. // 辅助数组来统计当前字符串中个是否有重复数字
  8. int[] countTable = new int[256];
  9. // 辅助标记,记录当前子字符串中,重复字母的个数
  10. int duplicateNum = 0;
  11. int left = -1;
  12. int right = 0;
  13. for (; right < str.length(); right++) {
  14. // 右指针代表子数组的右侧最后一个字符,记录当前字符的出现次数
  15. countTable[str.charAt(right)]++;
  16. if (countTable[str.charAt(right)] == 2) {
  17. duplicateNum++;
  18. }
  19. while (duplicateNum > 0) {
  20. // 如果有重复的字符,则移动左指针,直到没有重复字符为止
  21. left++;
  22. countTable[str.charAt(left)]--;
  23. if (countTable[str.charAt(left)] == 1) {
  24. duplicateNum--;
  25. }
  26. }
  27. maxLength = Math.max(maxLength, right - left);
  28. }
  29. return maxLength;
  30. }
  31. public static void main(String[] args) {
  32. System.out.println(findLongestSubString("babcca"));
  33. }
  34. }

字符可以隐式转换为数字,作为数组的下标在Java中,char 类型的字符可以隐式转换为对应的整数值,基于其在Unicode字符集中的编码。因为Unicode是ASCII的超集,ASCII值范围内的字符(即0到127)的Unicode编码与ASCII码相同。因此,在需要整数类型时,字符会自动转换为其相应的ASCII(或Unicode)码。
这就是为什么您可以直接在需要整数的上下文中使用字符,比如用作数组的索引。例如:

  1. 1char character = 'A'; // 'A' 在ASCII中的值是 65
  2. 2int asciiValue = character; // 字符 'A' 自动转换成整数 65
  3. 3int[] array = new int[128]; // 数组大到足以包含所有ASCII字符
  4. 4array[character] = 10; // 使用字符 'A' 作为索引赋值,等同于 array[65] = 10;

在上述代码中,character 变量是一个char类型,存储了字符 ‘A’。当将character赋值给整数变量asciiValue时,字符 ‘A’ 会自动转换为其ASCII值,也就是65。同样地,当将character用作数组array的索引时,它会被隐式转换为整数65,即数组的第66个元素(因为数组索引从0开始)。
需要注意的是,这种隐式转换是单向的,即可以将char隐式转换为int,但将int转换为char需要显式的类型转换:

  1. 1int number = 65;
  2. 2char convertedChar = (char) number; // 显式地将整数65转换为字符 'A'

在显式转换的情况下,您需要使用类型转换操作符(char)来指明您想要将整数转换为字符。

17:包含所有字符的最短字符串

:::info 题目:输入两个字符串s和t,请找出字符串s中包含字符串t的所有字符的最短子字符串。例如,输入的字符串s为”ADDBANCAD”,字符串t为”ABC”,则字符串s中包含字符’A’、’B’和’C’的最短子字符串是”BANC”。如果不存在符合条件的子字符串,则返回空字符串””。如果存在多个符合条件的子字符串,则返回任意一个。 :::

  1. public class minWindow17 {
  2. public static String minWindow(String s, String t) {
  3. if (s.length() < t.length()) {
  4. return "";
  5. }
  6. Map<Character, Integer> countTable = new HashMap<>();
  7. // 先统计t中所有字符的数量
  8. for (int i = 0; i < t.length(); i++) {
  9. countTable.put(t.charAt(i), countTable.getOrDefault(t.charAt(i), 0) + 1);
  10. }
  11. // 用来标记是否t中所有的字符包含了
  12. int countFlag = countTable.size();
  13. int minLength = Integer.MAX_VALUE;
  14. int minStart = 0;
  15. int minEnd = 0;
  16. // 然后双指针遍历s
  17. int left = 0;
  18. int right = 0;
  19. // 循环继续的条件
  20. // 条件1数组还没走完
  21. // 条件2数组走完了,也找到最小数组了,此时还可以移动左指针,找更小的数组
  22. while (right < s.length() || (countFlag == 0 && right == s.length())) {
  23. if (countFlag > 0) {
  24. // 还没找到包含t的数组,那就要移动右指针,同时确认新增的字符是否在t中
  25. char c = s.charAt(right);
  26. if (countTable.containsKey(c)) {
  27. // 如果有那就要减掉
  28. countTable.put(c, countTable.get(c) - 1);
  29. if (countTable.get(c) == 0) {
  30. // 如果当前字符全剪完了,要从flag中减掉
  31. countFlag--;
  32. }
  33. }
  34. right++;
  35. } else {
  36. // 如果count=0,就意味着当前left 到 right 中间的子数组已经包含了t
  37. // 此时要做两件事情:第一,判断当前子数组长度是否比之前的小
  38. if (right - left < minLength) {
  39. minLength = right - left;
  40. minStart = left;
  41. minEnd = right;
  42. }
  43. // 第二,尝试右移左指针,来看是否可能有更短的
  44. char c = s.charAt(left);
  45. if (countTable.containsKey(c)) {
  46. // 如果有那就要加回去
  47. countTable.put(c, countTable.get(c) + 1);
  48. if (countTable.get(c) == 1) {
  49. countFlag++;
  50. }
  51. }
  52. left++;
  53. }
  54. }
  55. return minLength == Integer.MAX_VALUE ? "" : s.substring(minStart, minEnd);
  56. }
  57. public static void main(String[] args) {
  58. String s = "asdfabcd";
  59. String t = "abd";
  60. System.out.println(minWindow(s, t));
  61. }
  62. }

18:有效的回文

:::info 题目:给定一个字符串,请判断它是不是回文。假设只需要考虑字母和数字字符,并忽略大小写。例如,”Was it a cat I saw?”是一个回文字符串,而”race a car”不是回文字符串。 :::

  1. public static boolean isPalindrome(String s) {
  2. int left = 0;
  3. int right = s.length() -1;
  4. while (left < right) {
  5. char leftChar = s.charAt(left);
  6. char rightChar = s.charAt(right);
  7. // 忽略除字符或者数字之外的其他字符
  8. if (!Character.isLetterOrDigit(leftChar)) {
  9. left++;
  10. } else if (!Character.isLetterOrDigit(rightChar)) {
  11. rightChar--;
  12. } else {
  13. // 左右比较
  14. char l = Character.toLowerCase(leftChar);
  15. char r = Character.toLowerCase(rightChar);
  16. if (l != r) {
  17. return false;
  18. }
  19. // 如果比较通过,则将两边的指针分别相向移动
  20. left++;
  21. right--;
  22. }
  23. }
  24. return true;
  25. }

19:最多删除一个字符得到回文

:::info 题目:给定一个字符串,请判断如果最多从字符串中删除一个字符能不能得到一个回文字符串。例如,如果输入字符串”abca”,由于删除字符’b’或’c’就能得到一个回文字符串,因此输出为true。 :::

  1. public class Palindrome19 {
  2. public static boolean isPalindrome(String str) {
  3. int left = 0;
  4. int right = str.length() - 1;
  5. // 第一次回文判断,允许有部队称发生
  6. while (left < right) {
  7. if (str.charAt(left) != str.charAt(right)) {
  8. break;
  9. }
  10. left++;
  11. right--;
  12. }
  13. if (left == right) {
  14. // 如果第一次就校验通过了,直接返回
  15. return true;
  16. } else {
  17. // 跳过左侧字符,或者右侧字符,只要有一个是回文就可以了
  18. return checkPalindrome(str, left + 1, right) || checkPalindrome(str, left, right + 1);
  19. }
  20. }
  21. public static boolean checkPalindrome(String str, int left, int right) {
  22. while (left < right) {
  23. if (str.charAt(left) != str.charAt(right)) {
  24. return false;
  25. }
  26. left++;
  27. right--;
  28. }
  29. return true;
  30. }
  31. public static void main(String[] args) {
  32. System.out.println(isPalindrome("qw1eewq"));
  33. System.out.println(isPalindrome("qw11eewq"));
  34. System.out.println(isPalindrome("qw1eew1q"));
  35. }
  36. }

20:回文子字符串的个数

:::info 题目:给定一个字符串,请问该字符串中有多少个回文连续子字符串?例如,字符串”abc”有3个回文子字符串,分别为”a”、”b”和”c”;而字符串”aaa”有6个回文子字符串,分别为”a”、”a”、”a”、”aa”、”aa”和”aaa”。 :::

  1. /**
  2. * @author jiaming
  3. * @version CountPalindrome20.java, v 0.1 2024年02月06日 19:16 jiaming
  4. */
  5. public class CountPalindrome {
  6. public static int countPalindrome(String str) {
  7. int count = 0;
  8. int centerIndex=0;
  9. for( ; centerIndex < str.length(); centerIndex++) {
  10. count += countPalindromeFromCenter(str, centerIndex, centerIndex);
  11. count += countPalindromeFromCenter(str, centerIndex, centerIndex+1);
  12. }
  13. return count;
  14. }
  15. private static int countPalindromeFromCenter(String str, int left , int right) {
  16. int count = 0;
  17. while(left >= 0 && right < str.length()) {
  18. if(str.charAt(left) == str.charAt(right)) {
  19. count++;
  20. left--;
  21. right++;
  22. } else {
  23. break;
  24. }
  25. }
  26. return count;
  27. }
  28. public static void main(String[] args) {
  29. System.out.println(countPalindrome("aaa"));
  30. }
  31. }