今天,我们来看两道中等题
题目一:最小替换子串长度
问题描述
小F得到了一个特殊的字符串,这个字符串只包含字符A、S、D、F,其长度总是4的倍数。他的任务是通过尽可能少的替换,使得A、S、D、F这四个字符在字符串中出现的频次相等。求出实现这一条件的最小子串长度。
测试样例
样例1:
输入:
input = "ADDF"
输出:1
样例2:
输入:
input = "ASAFASAFADDD"
输出:3
样例3:
输入:
input = "SSDDFFFFAAAS"
输出:1
样例4:
输入:
input = "AAAASSSSDDDDFFFF"
输出:0
样例5:
输入:
input = "AAAADDDDAAAASSSS"
输出:4
大致思路:
这道题我用的滑动窗口来解题。如果不知道滑动窗口是什么的,可以看这个视频 拿下滑动窗口! | LeetCode 209 长度最小的子数组_哔哩哔哩_bilibili
题解:
import java.util.HashMap;
import java.util.Map;
public class Main {
public static int solution(String input) {
int n = input.length();
int target = n / 4;
Map<Character, Integer> countMap = new HashMap<>();
// 初始化字符计数
for (char ch : input.toCharArray()) {
countMap.put(ch, countMap.getOrDefault(ch, 0) + 1);
}
// 检查是否已经符合目标频率
if (isBalanced(countMap, target)) {
return 0;
}
// 滑动窗口寻找最小子串长度
int left = 0, minLen = n;
for (int right = 0; right < n; right++) {
char rightChar = input.charAt(right);
countMap.put(rightChar, countMap.get(rightChar) - 1);
while (isBalanced(countMap, target)) {
minLen = Math.min(minLen, right - left + 1);
char leftChar = input.charAt(left);
countMap.put(leftChar, countMap.get(leftChar) + 1);
left++;
}
}
return minLen;
}
// 检查当前字符计数是否满足平衡条件
private static boolean isBalanced(Map<Character, Integer> countMap, int target) {
for (char ch : "ASDF".toCharArray()) {
if (countMap.getOrDefault(ch, 0) > target) {
return false;
}
}
return true;
}
public static void main(String[] args) {
System.out.println(solution("ADDF") == 1);
System.out.println(solution("ASAFASAFADDD") == 3);
System.out.println(solution("SSDDFFFFAAAS") == 1);
System.out.println(solution("AAAASSSSDDDDFFFF") == 0);
System.out.println(solution("AAAADDDDAAAASSSS") == 4);
}
}
具体步骤
-
初始化字符计数:遍历整个字符串,统计每个字符的出现次数。
-
检查初始平衡:如果初始状态下字符频次已经平衡,直接返回0。
-
滑动窗口寻找最小子串:
- 使用两个指针
left和right来表示窗口的左右边界。 - 移动
right指针,扩展窗口,并更新字符计数。 - 当窗口内的字符计数满足平衡条件时,记录当前窗口长度,并尝试缩小窗口(移动
left指针)。 - 继续移动
right指针,直到遍历完整个字符串。
- 使用两个指针
-
返回最小子串长度。
题目二:谈心猫的鱼干大分配
问题描述
在猫星球上,小R负责给一行排队的猫分发鱼干。每只猫有一个等级,等级越高的猫应该得到更多的鱼干。规则如下:
- 每只猫至少得到一斤鱼干。
- 如果一只猫的等级高于它相邻的猫,它就应该得到比相邻的猫更多的鱼干。
小R想知道,为了公平地满足所有猫的等级差异,他至少需要准备多少斤鱼干。
测试样例
样例1:
输入:
n = 3, cats_levels = [1, 2, 2]
输出:4
样例2:
输入:
n = 6, cats_levels = [6, 5, 4, 3, 2, 16]
输出:17
样例3:
输入:
n = 20, cats_levels = [1, 2, 2, 3, 3, 20, 1, 2, 3, 3, 2, 1, 5, 6, 6, 5, 5, 7, 7, 4]
输出:35
题解:
import java.util.ArrayList;
import java.util.List;
public class Main {
public static int solution(int n, List<Integer> cats_levels) {
int[] fishDry = new int[n];
for (int i = 0; i < n; i++) {
fishDry[i] = 1;
}
for (int i = 1; i < n; i++) {
if (cats_levels.get(i) > cats_levels.get(i - 1)) {
fishDry[i] = fishDry[i - 1] + 1;
}
}
for (int i = n - 2; i >= 0; i--) {
if (cats_levels.get(i) > cats_levels.get(i + 1)) {
fishDry[i] = Math.max(fishDry[i], fishDry[i + 1] + 1);
}
}
int totalFishDry = 0;
for (int fish : fishDry) {
totalFishDry += fish;
}
return totalFishDry;
}
public static void main(String[] args) {
List<Integer> catsLevels1 = new ArrayList<>();
catsLevels1.add(1);
catsLevels1.add(2);
catsLevels1.add(2);
List<Integer> catsLevels2 = new ArrayList<>();
catsLevels2.add(6);
catsLevels2.add(5);
catsLevels2.add(4);
catsLevels2.add(3);
catsLevels2.add(2);
catsLevels2.add(16);
List<Integer> catsLevels3 = new ArrayList<>();
catsLevels3.add(1);
catsLevels3.add(2);
catsLevels3.add(2);
catsLevels3.add(3);
catsLevels3.add(3);
catsLevels3.add(20);
catsLevels3.add(1);
catsLevels3.add(2);
catsLevels3.add(3);
catsLevels3.add(3);
catsLevels3.add(2);
catsLevels3.add(1);
catsLevels3.add(5);
catsLevels3.add(6);
catsLevels3.add(6);
catsLevels3.add(5);
catsLevels3.add(5);
catsLevels3.add(7);
catsLevels3.add(7);
catsLevels3.add(4);
System.out.println(solution(3, catsLevels1) == 4);
System.out.println(solution(6, catsLevels2) == 17);
System.out.println(solution(20, catsLevels3) == 35);
}
}
具体步骤:
-
初始分配:
- 每只猫至少得到一斤鱼干,所以首先将
fishDry数组的所有元素初始化为 1。
- 每只猫至少得到一斤鱼干,所以首先将
-
从左到右遍历:
- 从第二只猫开始,如果当前猫的等级高于前一只猫,则当前猫的鱼干数量应比前一只猫多 1。
-
从右到左遍历:
- 从倒数第二只猫开始,如果当前猫的等级高于后一只猫,则当前猫的鱼干数量应比后一只猫多 1,但要确保不小于当前已分配的鱼干数量。
-
计算总数:
- 最后,计算
fishDry数组中所有元素的和,即为所需的最少鱼干总数。
- 最后,计算