leetcode 420. Strong Password Checker

闾丘鸣
2023-12-01

A password is considered strong if below conditions are all met:

  1. It has at least 6 characters and at most 20 characters.
  2. It must contain at least one lowercase letter, at least one uppercase letter, and at least one digit.
  3. It must NOT contain three repeating characters in a row ("...aaa..." is weak, but "...aa...a..." is strong, assuming other conditions are met).

Write a function strongPasswordChecker(s), that takes a string s as input, and return the MINIMUM change required to make s a strong password. If s is already strong, return 0.

Insertion, deletion or replace of any one character are all considered as one change.

题目检测一个字符串变换成强口令需要的最少操作。

这里有3个检测条件。

  1. 条件1是长度限制。可以通过插入和删除解决。
  2. 条件2是字符类型。可以通过插入和替换解决。
  3. 条件3是连续相同字符长度限制。可以通过插入,删除,替换。 对于一个长为n的连续相同字符串。需要n/3次替换 or n/2次插入 or n-2 次删除。所以替换优于插入优于删除。

所以我们可以先执行替换操作。使得字符串满足条件3。

然后分情况讨论:

  1. 字符串长度l < 6 。需要6 - l次插入。可以用插入操作尽可能多的消除替换操作。
  2. 字符串长度l > 20。需要l - 20次删除。可以用删除操作尽可能多的消除替换操作。
  3. 字符串长度6 < l < 20 。只需要执行替换操作。

最后我们还需要检测插入+替换的操作次数是否大于缺少的字符类型。最终得到最少需要操作的次数。复杂度O(n)。代码如下:

/*
*@Auth PalaidnDu
*/
int max(int i1, int i2){
    return i1 > i2 ? i1 : i2;
}

int strongPasswordChecker(char * s){
    if(*s == '\0'){
        return 6;
    }
    int strLen = 0;
    //计算用了几种字符
    int useCharType = 0;
    int charTypeMap[256] = {0};
    int charTypeUse[4] = {0};
    for(int i = '0' ;i <= '9' ; ++i){
        charTypeMap[i] = 1;
    }
    for(int i = 'a' ; i <= 'z'; ++i){
        charTypeMap[i] = 2;
    }
    for(int i = 'A' ; i <= 'Z'; ++i){
        charTypeMap[i] = 3;
    }
    int needReplaceCharCount = 0;//需要replace的字符数
    int twoDelReplaceCount = 0; //替换replace操作只需要一个del的个数
    int onDelReplaceCount = 0;//替换replace操作需要两个del的个数
    char* p = s;//用于计算重复字符的长度
    char* start = s;//缓存s的开始,用于机选s的长度
    while(true){
        char c = *s;
        charTypeUse[charTypeMap[c]] = 1;//使用了这种类型的字符
        if(c != *p){//字符变化了
            int containCharLen = s - p;
            p = s;
            if(containCharLen >= 3){
                needReplaceCharCount += containCharLen/3;
                if(containCharLen%3==1){//需要两个del消除这个replace
                    ++twoDelReplaceCount;
                }else if(containCharLen%3==0){//需要1个del消除这个replace
                    ++onDelReplaceCount;
                }
            }
        }
        if(c == '\0'){
            break;
        }
        ++s;
    }
    strLen = s - start;
    int withoutCharTypeCount = 0;//缺失的类型
    for(int i = 1; i <=3 ; ++i){//统计需要添加多少种字符
        if(charTypeUse[i] == 0){
            ++withoutCharTypeCount;
        }
    }
    if(strLen < 6){//总是只执行insert 和 replace操作
        int needInsertCharCount = 6-strLen;
        //这里只考虑了插入和缺少类型的需求。是一个逻辑优化。当最短需求为6个字符时。可以只考虑这两个值。
        //如果最短长度较大应该先替换,然后使用插入的方式消除掉替换。
        return max(needInsertCharCount,withoutCharTypeCount);
    }else if(strLen > 20){//先执行replace,然后更具del的次数进行消除
        
        int needDelCharCount = strLen - 20;//需要删除的字符数
        int reduceDel = needDelCharCount;
        //尽可能多的抵消替换操作
        if(reduceDel > onDelReplaceCount){//优先抵消只需要1个del
            reduceDel -= onDelReplaceCount;
            needReplaceCharCount -= onDelReplaceCount;
            if(reduceDel > twoDelReplaceCount){//再抵消只需要2个del
                needReplaceCharCount -= twoDelReplaceCount;
                reduceDel -= 2*twoDelReplaceCount;
                needReplaceCharCount -= reduceDel/3;//剩余的del 。每3个del可以抵消一个replace
            }else{
                needReplaceCharCount -= reduceDel/2;
            }
        }else{
            needReplaceCharCount -= reduceDel;
        }
        return needDelCharCount + max(withoutCharTypeCount,needReplaceCharCount);
    }else{//总是只执行replace
        return max(needReplaceCharCount,withoutCharTypeCount);
    }
    
}

 

 类似资料:

相关阅读

相关文章

相关问答