最小替换长度| 豆包MarsCode AI 刷题

129 阅读4分钟

最小替换长度

问题描述

你有一个长度为4的倍数的字符串,该字符串仅由字母A,S,DF组成。你的任务是找到一个最小的字串,将这个字串中的字符替换为另外一些字符,从而使整个字符串中每个字母A,S,D,F的出现次数相等

问题解析

  1. 目标:

    我们要找到一个最小的字串,将其替换,使得替换后的整个字符串中每个字母的频率相同。

    2.频次目标:

    由于字符串长度是4的倍数,我们可以推算出每个字母的目标频率应该是length/4.

    3.滑动窗口:

    我们可以使用滑动窗口技术来找到最小的需要替换的子串。

解决思路:

1.计算每个字符的出现次数:

首先统计每个字符A,S,D,F的出现次数。

2.初始化窗口:

用双指针技术初始化窗口,右指针扩展窗口,左指针缩小窗口,确保窗口内的字符频率符合要求。

3.检查当前窗口是否满足条件:

如果满足条件,则计算窗口大小,并记录最小窗口长度。

4.更新窗口:

滑动窗口更新。继续寻找直到找到最小的需要替换的子串。

这滑动窗口技术是啥子嘞🤔问下豆包
滑动窗口技术是一种常用的算法技术,适用于解决一类子序列或子数组问题的题目。欢动窗口可以帮助我们高效的在数组或字符串中找到满足某些条件的子序列或子数组。Marscode也是给我讲了个例子帮助我理解👍

假设我们有一个数组 [1, 3, 2, 4, 5, 7, 2],我们需要找到一个和为 9 的子数组。滑动窗口可以帮助我们高效地找到这个子数组。


public class SlidingWindowExample {
    public static int[] findSubArrayWithSum(int[] array, int target) {
        int left = 0;
        int sum = 0;

        for (int right = 0; right < array.length; right++) {
            sum += array[right];

            // 当窗口内的和大于目标值时,移动左指针缩小窗口
            while (sum > target) {
                sum -= array[left];
                left++;
            }

            // 当窗口内的和等于目标值时,返回窗口的起始和结束位置
            if (sum == target) {
                return new int[]{left, right};
            }
        }
        
        // 如果没有找到满足条件的子数组,返回空数组
        return new int[]{};
    }

    public static void main(String[] args) {
        int[] array = {1, 3, 2, 4, 5s, 7, 2};
        int target = 9;
        int[] result = findSubArrayWithSum(array, target);
        if (result.length == 0) {
            System.out.println("No subarray found");
        } else {
            System.out.println("Subarray found from index " + result[0] + " to " + result[1]);
        }
    }
}

✍应用

1.找到数组或字符串中的子序列或子数组

2.计算满足特定条件的子序列或子数组

1.找到具有特定属性(如最小或最大长度,特定字符频率等)的子序列或子数组

还有双指针技术🤠

同向双指针通常用于滑动窗口问题,两个指针起始位置相同或者一个在前一个在后,同时向一个方向移动。常见应用包括找到具有特定属性的子数组或子字符串。

找到数组中和为特定值的最长字符串🐱‍💻

public class SameDirectionTwoPointers {
    public static int findLongestSubarrayWithSum(int[] nums, int target) {
        int left = 0, right = 0, sum = 0, maxLength = 0;
        while (right < nums.length) {
            sum += nums[right];
            while (sum > target) {
                sum -= nums[left];
                left++;
            }
            if (sum == target) {
                maxLength = Math.max(maxLength, right - left + 1);
            }
            right++;
        }
        return maxLength;
    }

    public static void main(String[] args) {
        int[] nums = {1, 2, 1, 1, 1, 2, 3, 1};
        int target = 4;
        System.out.println(findLongestSubarrayWithSum(nums, target)); // 输出:3
    }
}

①分析目标频次

每个字母的目标频次为length/4,这里记为k

②统计每个字母的初始频次 ③判断是否已经满足条件

如果每个字母的频次都等于目标频次k,则说明已经满足要求,直接返回0

④使用滑动窗口技术找到最小字串

初始化两个指针 leftright,用于表示滑动窗口的左右边界

使用 right 指针遍历字符串,每次将 right 所指向的字符移出当前的字符频次计数。

检查当前窗口内的频次是否符合要求。如果窗口内的频次满足条件,尝试移动 left 指针缩小窗口,并更新最小子串长度。

如果当前窗口不符合要求,继续扩展窗口(移动 right 指针)。

当当当题解😄

public class Main {
    public static int solution(String input) {
        int n = input.length();
        int k = n / 4; // 每个字母的目标频次

        // 统计每个字母出现的次数
        int[] count = new int[4];
        for (char c : input.toCharArray()) {
            if (c == 'A') count[0]++;
            else if (c == 'S') count[1]++;
            else if (c == 'D') count[2]++;
            else if (c == 'F') count[3]++;
        }

        // 如果所有字母频次已经符合要求,则返回0
        if (count[0] == k && count[1] == k && count[2] == k && count[3] == k) {
            return 0;
        }

        // 滑动窗口,寻找最小子串
        int left = 0, minLength = n;
        for (int right = 0; right < n; right++) {
            if (input.charAt(right) == 'A') count[0]--;
            else if (input.charAt(right) == 'S') count[1]--;
            else if (input.charAt(right) == 'D') count[2]--;
            else if (input.charAt(right) == 'F') count[3]--;

            // 检查当前窗口是否满足条件
            while (count[0] <= k && count[1] <= k && count[2] <= k && count[3] <= k) {
                minLength = Math.min(minLength, right - left + 1);
                if (input.charAt(left) == 'A') count[0]++;
                else if (input.charAt(left) == 'S') count[1]++;
                else if (input.charAt(left) == 'D') count[2]++;
                else if (input.charAt(left) == 'F') count[3]++;
                left++;
            }
        }

        return minLength;
    }

    public static void main(String[] args) {
        System.out.println(solution("ADDF") == 1); // 样例1
        System.out.println(solution("ASAFASAFADDD") == 3); // 样例2
    }
}

感恩字节跳动,感恩MarsCode AI,感恩青训营❤