JAVA练习235-强密码检验器

题目概述

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

  • 由至少 6 个,至多 20 个字符组成。
  • 至少包含 一个小写 字母,一个大写 字母,和 一个数字 。
  • 同一字符 不能 连续出现三次 (比如 "...aaa..." 是不允许的, 但是 "...aa...a..." 如果满足其他条件也可以算是强密码)。
  • 给你一个字符串 password ,返回 将 password 修改到满足强密码条件需要的最少修改步数。如果 password 已经是强密码,则返回 0 。

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

  • 插入一个字符到 password ,
  • 从 password 中删除一个字符,或
  • 用另一个字符来替换 password 中的某个字符。

示例 1:

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

示例 2:

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

示例 3:

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

提示:

  • 1 <= password.length <= 50
  • password 由字母、数字、点 '.' 或者感叹号 '!'

题目来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/strong-password-checker

解题分析

方法:模拟

本题无非三种情况,根据字符串长度进行模拟,我们令长度为 len:

  1. len < 6 时,我们需要进行的操作显然只有添加,影响添加的因素只有大小写字母和数字是否出现,我们可以先遍历记录这三种种类的个数,令为 category,那么我们需要添加的个数就是 6 - len 和 3 - category 的最大值。
  2. 6 <= len <= 20,我们需要进行的操作显然只有替换,因此我们只需要记录连续相同字符出现的个数,然后将它的每三个字符替换为其他字符即可,即相同个数整除 3,即替换的次数,最后和 3 - category 进行比较返回最大值即可。
  3. len > 20 时,我们需要进行的操作分为删除和替换,而替换操作可以用删除操作来代替,比如出现 3 个相同字符,删除一个和替换一个一样,可以省去操作次数,因此我们可以利用一个数组来记录连续相同字符出现次数除以3的余数的个数,再对这些余数进行操作,记录可以省去的最大值,然后将省去后的次数加上删除的次数和 3 - category 比较返回最大值即可。

时间复杂度:O(n)        n 为字符串长度
空间复杂度:O(n)        将字符串转化为字符数组为 O(n),直接在原字符串上操作就是 O(1)

class Solution {
    public int strongPasswordChecker(String password) {
        //字符数组
        char[] cs = password.toCharArray();
        //字符串长度
        int len = cs.length;
        //记录大小写字母和数字的数量
        int upper = 0, lower = 0, num = 0;
        //遍历
        for(char c: cs){
            if(c >= 'A' && c <= 'Z'){
                upper = 1;
            }
            else if(c >= 'a' && c <= 'z'){
                lower = 1;
            }else if(c >= '0' && c <= '9'){
                num = 1;
            }
        }
        //记录没有的字符种类
        int category = 3 - upper - lower - num;
        //字符串长度小于6
        if(len < 6){
            return Math.max(6 - len, category);
        }
        //记录修改次数
        int update = 0;
        //记录取余3之后的数的数量
        int[] nums = new int[3];
        //遍历寻找连续出现三次以上字符
        for(int i = 0; i < len-1; ++i){
            //记录相同字符数量
            int same = 1;
            while(i < len-1 && cs[i] == cs[i+1]){
                same++;
                ++i;
            }
            if(same > 2){
                update += same / 3;
                nums[same % 3]++;
            }
        }
        //字符串长度在范围内
        if(len <= 20){
            return Math.max(update, category);
        }
        //长度大于20
        //定义要删除的次数
        int del = len - 20, cur = del;
        //根据余数进行遍历
        for(int i = 0; i < 3; ++i){
            if(i == 2){
                nums[i] = update;
            }
            if(cur > 0){
                int temp = Math.min(nums[i] * (i + 1), cur);
                cur -= temp;
                update -= temp / (i+1);
            }
        }
        return del + Math.max(update, category);
    }
}

 

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

什巳

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值