420. Strong Password Checker [leetcode]

思路:
有三个问题需要解决:
1、缺失字符种类问题(大写,小写、数字) 可用操作:replace,insert
2、长度问题 可用该操作:insert(< 6),delete(> 20)
3、重复问题 可用操作: replace,insert,delete,其中replace的解决方法最优。

可以看到各种问题之间是有重复性的,也就是说可以通过解决某个问题,同时解决另一个问题。
我们试图找到一种途径能够在解决一个问题的同时解决(或者说缓解)其他问题。
根据观察:
长度小于6时,解决问题2的同时,可以解决(缓解)1,3,因此先考虑2,再利用2解决1,3。
长度大于20时,解决问题1可以缓解3(delete),解决问题2也可以缓解3(replace),由于replace操作并不能减少delete操作的步数,而delete操作可以减少(缓解)replace的操作步数,delete应当优先于replace操作(比如……AAA,先delete成……AA,就可以减少一步replace的操作了)。
长度<=20,>=6时,可通过解决1来解决3(优先replace)。

因此我们分情况讨论:

首先对于小于6的情况,必须的操作为insert。 根据推理,需要的操作步数为: step = 缺失字符种类数 + 字符串长度 > 6 ? 缺失字符种类数 : 6 - 字符串长度

对于大于20的情况,我们首先先解决多余出来的字符,delete操作必须要保证能最大限度地缓解问题,也就是使得之后重复字符串中需要replace的步数最少。我们尽量保证所有连续的字符串能变成(长度 % 3) = 2的状态。我们首先通过一步delete使得将每个长度为3的倍数的连续字符串变成 (长度 % 3) = 2的状态,然后再通过两步delete,使得每个 (长度 % 3) = 1 的连续字符串变成 (长度 % 3) = 2的状态,再通过三步delete 使得每个 (长度 % 3) = 2 的连续字符串变成 (长度 % 3) = 2的状态。
完成delete后由于长度变成了<=20. 我们可以将问题转化成<=20,>=6的情况:

检查问题1,计算出所需要的解决步骤step1,检查是否有问题3,计算出需要的解决步骤step3, 若step3 <= step1, 则我们只要解决问题1就能彻底解决问题3,因此最后的step = step1;若step3 > step1, 则说明,解决问题1能解决部分问题3,最后所需step = step3;

以下为代码部分:

class Solution {
public:
    int strongPasswordChecker(string s) {
        bool upper = false, lower = false, digit = false;
        int step = 0;
        vector<int> repeat;
        int start = 0;
        int size = s.size();
        for (int i = 0; i < s.size(); i++) {
            if (s[i] >= 'A' && s[i] <= 'Z')
                upper = true;
            else if (s[i] >= 'a' && s[i] <= 'z' )
                lower = true;
            else if (s[i] >= '0' && s[i] <= '9')
                digit = true;
            start = i;
            while (i < s.size() - 1 && s[i] == s[i + 1]){
                i++;
            }
            if (i - start >= 2) 
                repeat.push_back(i - start + 1); 
        }
        if (upper && lower && digit && repeat.size() == 0 && size <= 20 && size >= 6) return 0;
        int must = 0;
        if (!upper) must++;
        if (!lower) must++;
        if (!digit) must++;
        step += must;

        if (size < 6) {
            if (size + must < 6) step = 6 - size;  
        }
        else {
        // 解决 overLength  的问题(>20)
            int overLen = size - 20 > 0 ? size - 20 : 0;
            for (int i = 0; i < 3 && overLen; i++) {
                for (vector<int>::iterator it = repeat.begin(); it != repeat.end() && overLen; ) {
                    if ( *it % 3 == i) {
                        int tmp =  ((i + 1) > overLen) ? overLen : (i + 1);
                        *it -= tmp;
                        overLen -= tmp;
                        step += tmp;
                        if (*it < 3) {
                            it = repeat.erase(it);
                            continue;
                        } 
                    }
                    it++;
                }
            }
            step += overLen;
            //此时长度 >= 6, <= 20
            int left = 0;
            for (auto i : repeat)
                left += i / 3;
            step += left > must ? left - must : 0; 
        }
        return step;

    }
};
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值