尽可能使字符串相等

132 阅读1分钟

题目

前缀和 + 二分查找

class Solution {
    public int equalSubstring(String s, String t, int maxCost) {

        // s变成t只能在对应位置上的字符发生变化, 也就是只能s.charAt(0)变成t.charAt(0)
        // 不能是s.charAt(0)变成t.charAt(1)
        // 计算出对应位置上的差值
        int [] diff = new int[s.length()];
        for (int i = 0; i < s.length(); i ++) {
            diff[i] = Math.abs(t.charAt(i) - s.charAt(i));
        }

        // 问题转化成求diff数组中连续子数组的元素和小于maxCost的最大长度
        // diff[i] + diff[i + 1] + .... + diff[j] <= maxCost 时, j - i的最大值
        // 利用前缀和数组accDiff[i] = diff[0] + diff[1] + ... + diff[i]
        int [] accDiff = new int[s.length()];
        for (int i = 0; i < s.length(); i ++) {
            if (i == 0) {
                accDiff[i] = diff[0];
            } else {
                accDiff[i] = accDiff[i - 1] + diff[i];
            }
        }

        int maxLength = 0;
        for(int i = 0; i < accDiff.length; i ++) {
            // accDiff[j] - accDiff[i] + diff[i] <= maxCost
            // i为左边界, 寻找accDiff[i] + maxCost - diff[i]的右边界j的值
            // accDiff为有序数组, 单调增, 利用二分查找
            int target = accDiff[i] + maxCost - diff[i];
            int j = binarySearch(accDiff, target, i, accDiff.length);
            maxLength = Math.max(maxLength, j - i);

        }

        return maxLength;
    }

    private int binarySearch(int [] accDiff, int target, int start, int end) {
        if (start == end) {
            return start;
        }
        int mid = start + (end - start) / 2;
        if (accDiff[mid] == target) {
            // 为了解决数组中重复元素
            return binarySearch(accDiff, target, mid + 1, end);
        } else if (accDiff[mid] < target) {
            return binarySearch(accDiff, target, mid + 1, end);
        } else {
            return binarySearch(accDiff, target, start, mid);
        }
    }
}

基本思路

  1. 首先读懂题目, 字符串s中i位置的字符只能变成t字符串中i位置的字符, 而i不能变j.

  2. 将题目转化成求差分数组连续和小于等于某个值的最大长度

  3. 利用前缀和计算连续数组和

  4. 因为是有序数组, 因此可以用二分查找法, 寻找满足条件的最大长度.