列表

详情


420. 强密码检验器

 

如果一个密码满足下述所有条件,则认为这个密码是强密码:

给你一个字符串 password ,返回 password 修改到满足强密码条件需要的最少修改步数。如果 password 已经是强密码,则返回 0

在一步修改操作中,你可以:

 

示例 1:

输入:password = "a"
输出:5

示例 2:

输入:password = "aA1"
输出:3

示例 3:

输入:password = "1337C0d3"
输出:0

 

提示:

原站题解

去查看

上次编辑到这里,代码来自缓存 点击恢复默认模板
class Solution { public: int strongPasswordChecker(string password) { } };

javascript 解法, 执行用时: 56 ms, 内存消耗: 41 MB, 提交时间: 2023-01-10 09:45:29

/**
 * @param {string} password
 * @return {number}
 */
var strongPasswordChecker = function(password) {
    const n = password.length;
    let hasLower = 0, hasUpper = 0, hasDigit = 0;
    for (let i = 0; i < n; ++i) {
        const ch = password[i];
        if (isLowerCase(ch)) {
            hasLower = 1;
        } else if (isUpperCase(ch)) {
            hasUpper = 1;
        } else if (isDigit(ch)) {
            hasDigit = 1;
        }
    }
    const categories = hasLower + hasUpper + hasDigit;

    if (n < 6) {
        return Math.max(6 - n, 3 - categories);
    } else if (n <= 20) {
        let replace = 0;
        let cnt = 0;
        let cur = '#';

        for (let i = 0; i < n; ++i) {
            const ch = password[i];
            if (ch === cur) {
                ++cnt;
            } else {
                replace += Math.floor(cnt / 3);
                cnt = 1;
                cur = ch;
            }
        }
        replace += Math.floor(cnt / 3);
        return Math.max(replace, 3 - categories);
    } else {
        // 替换次数和删除次数
        let replace = 0, remove = n - 20;
        // k mod 3 = 1 的组数,即删除 2 个字符可以减少 1 次替换操作
        let rm2 = 0;
        let cnt = 0;
        let cur = '#';

        for (let i = 0; i < n; ++i) {
            const ch = password[i];
            if (ch === cur) {
                ++cnt;
            } else {
                if (remove > 0 && cnt >= 3) {
                    if (cnt % 3 === 0) {
                        // 如果是 k % 3 = 0 的组,那么优先删除 1 个字符,减少 1 次替换操作
                        --remove;
                        --replace;
                    } else if (cnt % 3 === 1) {
                        // 如果是 k % 3 = 1 的组,那么存下来备用
                        ++rm2;
                    }
                    // k % 3 = 2 的组无需显式考虑
                }
                replace += Math.floor(cnt / 3);
                cnt = 1;
                cur = ch;
            }
        }
        if (remove > 0 && cnt >= 3) {
            if (cnt % 3 === 0) {
                --remove;
                --replace;
            } else if (cnt % 3 === 1) {
                ++rm2;
            }
        }
        replace += Math.floor(cnt / 3);

        // 使用 k % 3 = 1 的组的数量,由剩余的替换次数、组数和剩余的删除次数共同决定
        const use2 = Math.min(Math.min(replace, rm2), Math.floor(remove / 2));
        replace -= use2;
        remove -= use2 * 2;
        // 由于每有一次替换次数就一定有 3 个连续相同的字符(k / 3 决定),因此这里可以直接计算出使用 k % 3 = 2 的组的数量
        const use3 = Math.min(replace, Math.floor(remove / 3));
        replace -= use3;
        remove -= use3 * 3;
        return (n - 20) + Math.max(replace, 3 - categories);
    }
};

const isLowerCase = (ch) => {
    return 'a' <= ch && ch <= 'z';
}

const isUpperCase = (ch) => {
    return 'A' <= ch && ch <= 'Z';
}

const isDigit = (ch) => {
    return parseFloat(ch).toString() === "NaN" ? false : true;
}

golang 解法, 执行用时: 0 ms, 内存消耗: 1.9 MB, 提交时间: 2023-01-10 09:44:51

func strongPasswordChecker(password string) int {
    hasLower, hasUpper, hasDigit := 0, 0, 0
    for _, ch := range password {
        if unicode.IsLower(ch) {
            hasLower = 1
        } else if unicode.IsUpper(ch) {
            hasUpper = 1
        } else if unicode.IsDigit(ch) {
            hasDigit = 1
        }
    }
    categories := hasLower + hasUpper + hasDigit

    switch n := len(password); {
    case n < 6:
        return max(6-n, 3-categories)
    case n <= 20:
        replace, cnt, cur := 0, 0, '#'
        for _, ch := range password {
            if ch == cur {
                cnt++
            } else {
                replace += cnt / 3
                cnt = 1
                cur = ch
            }
        }
        replace += cnt / 3
        return max(replace, 3-categories)
    default:
        // 替换次数和删除次数
        replace, remove := 0, n-20
        // k mod 3 = 1 的组数,即删除 2 个字符可以减少 1 次替换操作
        rm2, cnt, cur := 0, 0, '#'
        for _, ch := range password {
            if ch == cur {
                cnt++
                continue
            }
            if remove > 0 && cnt >= 3 {
                if cnt%3 == 0 {
                    // 如果是 k % 3 = 0 的组,那么优先删除 1 个字符,减少 1 次替换操作
                    remove--
                    replace--
                } else if cnt%3 == 1 {
                    // 如果是 k % 3 = 1 的组,那么存下来备用
                    rm2++
                }
                // k % 3 = 2 的组无需显式考虑
            }
            replace += cnt / 3
            cnt = 1
            cur = ch
        }

        if remove > 0 && cnt >= 3 {
            if cnt%3 == 0 {
                remove--
                replace--
            } else if cnt%3 == 1 {
                rm2++
            }
        }

        replace += cnt / 3

        // 使用 k % 3 = 1 的组的数量,由剩余的替换次数、组数和剩余的删除次数共同决定
        use2 := min(min(replace, rm2), remove/2)
        replace -= use2
        remove -= use2 * 2

        // 由于每有一次替换次数就一定有 3 个连续相同的字符(k / 3 决定),因此这里可以直接计算出使用 k % 3 = 2 的组的数量
        use3 := min(replace, remove/3)
        replace -= use3
        remove -= use3 * 3
        return (n - 20) + max(replace, 3-categories)
    }
}

func max(a, b int) int {
    if b > a {
        return b
    }
    return a
}

func min(a, b int) int {
    if a > b {
        return b
    }
    return a
}

python3 解法, 执行用时: 36 ms, 内存消耗: 15.1 MB, 提交时间: 2023-01-10 09:44:33

class Solution:
    def strongPasswordChecker(self, password: str) -> int:
        n = len(password)
        has_lower = has_upper = has_digit = False
        for ch in password:
            if ch.islower():
                has_lower = True
            elif ch.isupper():
                has_upper = True
            elif ch.isdigit():
                has_digit = True
        
        categories = has_lower + has_upper + has_digit

        if n < 6:
            return max(6 - n, 3 - categories)
        elif n <= 20:
            replace = cnt = 0
            cur = "#"

            for ch in password:
                if ch == cur:
                    cnt += 1
                else:
                    replace += cnt // 3
                    cnt = 1
                    cur = ch
            
            replace += cnt // 3
            return max(replace, 3 - categories)
        else:
            # 替换次数和删除次数
            replace, remove = 0, n - 20
            # k mod 3 = 1 的组数,即删除 2 个字符可以减少 1 次替换操作
            rm2 = cnt = 0
            cur = "#"

            for ch in password:
                if ch == cur:
                    cnt += 1
                else:
                    if remove > 0 and cnt >= 3:
                        if cnt % 3 == 0:
                            # 如果是 k % 3 = 0 的组,那么优先删除 1 个字符,减少 1 次替换操作
                            remove -= 1
                            replace -= 1
                        elif cnt % 3 == 1:
                            # 如果是 k % 3 = 1 的组,那么存下来备用
                            rm2 += 1
                        # k % 3 = 2 的组无需显式考虑
                    replace += cnt // 3
                    cnt = 1
                    cur = ch
            
            if remove > 0 and cnt >= 3:
                if cnt % 3 == 0:
                    remove -= 1
                    replace -= 1
                elif cnt % 3 == 1:
                    rm2 += 1
            
            replace += cnt // 3

            # 使用 k % 3 = 1 的组的数量,由剩余的替换次数、组数和剩余的删除次数共同决定
            use2 = min(replace, rm2, remove // 2)
            replace -= use2
            remove -= use2 * 2
            # 由于每有一次替换次数就一定有 3 个连续相同的字符(k / 3 决定),因此这里可以直接计算出使用 k % 3 = 2 的组的数量
            use3 = min(replace, remove // 3)
            replace -= use3
            remove -= use3 * 3
            return (n - 20) + max(replace, 3 - categories)

上一题