『Leetcode 5232』替换子串得到平衡字符串

『题目』:

 有一个只含有 'Q','W', 'E', 'R' 四种字符,且长度为 n 的字符串。

假如在该字符串中,这四个字符都恰好出现 n/4 次,那么它就是一个「平衡字符串」。

给你一个这样的字符串s,请通过「替换子串」的方式,使原字符串 s 变成一个「平衡字符串」。

你可以用和「待替换子串」长度相同的 任何 其他字符串来完成替换。

请返回待替换子串的最小可能长度。

如果原字符串自身就是一个平衡字符串,则返回 0

『限制条件』:

1 <= s.length <= 10^5
s.length 是 4 的倍数
s 中只含有 'Q', 'W', 'E', 'R' 四种字符

『输入输出』

输入:s = "QWER"
输出:0
解释:s 已经是平衡的了。

输入:s = "QQWE"
输出:1
解释:我们需要把一个 'Q' 替换成 'R',这样得到的 "RQWE" (或 "QRWE") 是平衡的。

输入:s = "QQQW"
输出:2
解释:我们可以把前面的 "QQ" 替换成 "ER"。 

输入:s = "QQQQ"
输出:3
解释:我们可以替换后 3 个 'Q',使 s = "QWER"。

『题解』:

这道题目的意思是找一个子串,只能对这个子串的字母进行替换,然后使原串变成平衡串

  • 首先可以根据输入的原串length,得到每个字符pingjun=length/4的个数
  • 原串的每个字符的个数为sums[i],我们知道要变的字符,肯定是那种比pingjun要多的字符,那么就可以统计一下v[i]=sums[i]-pingjun >= 0 ? sums[i]-pingjun : 0,这就是说,我们要找到一个子串的长度为len,该长度能够包含v[i]中的每个字符多出的个数。
  • 这么就很好办了,我们可以从len=(0,length),来二分枚举长度,因为明显,len越大,所包含的字符肯定越多。如果当前len的长度的所有子串中,有包含v[i]的每个字符的个数,len=(0,mid-1),继续枚举;如果没有包含,就len=(mid+1,len)继续枚举。

『实现』:

public class test26 {

    public boolean check(int[][] qianzhui,int[] sums,int len,int length)
    {
        for(int i = 0; i + len <= length;i++)
        {
            boolean flag = true;
            for(int j = 0; j < 4 ;j++)
            {
                if(!(qianzhui[i + len][j] - qianzhui[i][j] >= sums[j]))
                {
                    flag = false;
                    break;
                }
            }

            if(flag) return true;
        }

        return false;
    }


    public int balancedString(String s) {

        int len = 0;
        if(s.length() % 4 != 0) return -1;

        int length = s.length();
        char[] cs = new char[length];
        int [][] qianzhui = new int[length + 1][4];
        int [] sums = new int[4];
        s.getChars(0,length,cs,0);

        for(int i = 0;i < 4;i++)
        {
            sums[i] = 0;
            qianzhui[0][i] = 0;
        }

        for(int i = 0;i < length;i++)
        {
            for(int j = 0;j < 4;j++) qianzhui[i + 1][j] = qianzhui[i][j];

            switch (cs[i])
            {
                case 'Q':
                    sums[0]++;
                    qianzhui[i + 1][0] ++;
                    break;
                case 'W':
                    sums[1]++;
                    qianzhui[i + 1][1] ++;
                    break;
                case 'E':
                    sums[2]++;
                    qianzhui[i + 1][2] ++;
                    break;
                case 'R':
                    sums[3]++;
                    qianzhui[i + 1][3] ++;
                    break;
            }
        }

        int pingjun = length / 4;
        for(int i = 0;i < 4;i++)
        {
            if(sums[i] - pingjun >= 0)
            {
                sums[i] = sums[i] - pingjun;
                len += sums[i];
            }
            else sums[i] = 0;
        }

        int left = len;
        int right = s.length();
        int mid;
        int ans = right;

        while(left <= right)
        {
            mid = (left + right) / 2;
            if(check(qianzhui,sums,mid,length))
            {
                ans = mid;
                right = mid - 1;
            }
            else left = mid + 1;
        }

        return ans;
    }

    public static void main(String[] args) {

        test26 of = new test26();
        String s = "QQQQ";
        System.out.println(of.balancedString(s));
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值