420. Strong Password Checker

不定期更新leetcode解题java答案。

采用pick one的方式选择题目。

  本题为密码检测程序,给定字符串,要求1、字符串长度在6~20之间,2、字符串至少包含小写字母、大写字母和数字,3、字符串不允许存在3个连续的相同字符。(如:"aaa")

  问:需要几次变换操作可以将给定字符串改写为规范密码字符串。变换操作包括:1、插入一个字符,2、删除一个字符,3、修改一个字符。

  首先考虑长度问题,如果小于6个或者大于20个字符,每多一个字符必须做出一次处理,如果少则插入;多则删除。

  然后考虑字符类型问题,每少一种字符类型则需要插入或者修改处理。

  最后关于连字符串,则可以采用修改、插入、删除,三种方式来进行处理。

  我们分析一下这三种方式对三种要求的影响:

  1、对长度的关系是最直接的,小则加,大则删,N——N;变化不能增加长度。

  2、若字符类型少,采用插入或者修改对其影响相同,N——N;删除不能增加类型。

  3、若存在连续字符,试考虑对一个长度为N的连续字符,删除操作:重复字符长度减1,N——N-1;插入操作:重复字符长度减2,N——N-2;修改操作:重复字符长度-3,N——N-3。

  

  有如上规则可以试想长度若小,则增加的时候尽量增加字符类型,并且由于插入时可以减少存在连续字符的长度,如:"aaaaab",插入后可变为"aaa1aab",由于本题中长度最低限度较小,偷懒没有将插入的分析加入(因为连续字符不满足要求的最小长度是3,这个东西可以看下文以及代码进行理解)。若长度较大,则进行删除操作,此时应尽可能满足删除连续字符长度为3的倍数中的字符,其次为连续字符长度为3的倍数+1中的字符(为了删除操作多时尽可能的减少之后的修改操作,后文会提到),最后是删除连续字符长度为3的倍数+2中的字符。

  此时完成了长度要求,若长度要求满足,种类缺少,我们尽可能采用修改操作,不考虑插入操作。由于插入操作不只变换了长度(影响了第一步),而且插入操作减少连续字符的数量也没有修改操作多:N-2变化的小于N-3。

  最后是对存在的连续字符进行操作,通过上述分析,很明显可以看出使用修改操作最小化操作次数。

  由上可得如下代码:

 1 public class Solution {
 2     public int strongPasswordChecker(String s) {
 3         boolean hasDigit = false, hasLowercase = false, hasUppercase = false;
 4         
 5         char lastChar = ' ';
 6         int count = 1;
 7         ArrayList<Integer> repeatCounts = new ArrayList<Integer>();
 8         
 9         for(int i = 0; i < s.length(); i++){
10             char tmpChar = s.charAt(i);
11             
12             //判断是否存在要求的字符
13             if(tmpChar <= '9' && tmpChar >= '0')
14                 hasDigit = true;
15             else if(tmpChar <= 'Z' && tmpChar >= 'A')
16                 hasUppercase = true;
17             else if(tmpChar <= 'z' && tmpChar >= 'a')
18                 hasLowercase = true;
19                 
20             //统计超过3连字符串的数量以及对应的个数
21             if(lastChar == tmpChar){
22                 count++;
23             }else{
24                 if(count >= 3)
25                     repeatCounts.add(count);
26                 
27                 count = 1;
28             }
29             lastChar = tmpChar;
30         }
31         //循环结束后没有处理当前统计长度
32         if(count >= 3)
33             repeatCounts.add(count);
34         
35         //记录长度问题
36         int lengthDifference = 0;
37         if(s.length() > 20)
38             lengthDifference = s.length() - 20;
39         else
40             lengthDifference = s.length() < 6 ? s.length() - 6 : 0;
41             
42         int steps = Math.abs(lengthDifference);
43         
44         int types = (hasDigit ? 0 : 1) + (hasUppercase ? 0 : 1) + (hasLowercase ? 0 : 1);
45         
46         //先满足长度要求
47         if(lengthDifference < 0){
48             while(lengthDifference != 0){
49                 lengthDifference++;
50                 types--;
51                 //本题中如果长度小,那么插入一个即可消除全部3连的
52                 repeatCounts.clear();   //这里偷懒了,如果字符串长度要求下限较大则应采用添加的方式进行处理,类同删除操作:条件稍微变化,N-1变为N-2
53             }
54         }else if(lengthDifference > 0){
55             while(lengthDifference != 0){
56                 lengthDifference--;
57                 if(repeatCounts.size() != 0){
58                     //删除操作 循环3次用于考虑先减哪种长度的连串
59                     for(int i = 0; i < repeatCounts.size() * 3; i++){
60                         int loc = i % repeatCounts.size();
61                         if(repeatCounts.get(loc) % 3 == 0){
62                             repeatCounts.set(loc, repeatCounts.get(loc) - 1);
63                             break;
64                         }
65                         if(i >= repeatCounts.size() && repeatCounts.get(loc) % 3 == 1 && repeatCounts.get(loc) > 3){
66                             repeatCounts.set(loc, repeatCounts.get(loc) - 1);
67                             break;
68                         }
69                         if(i >= repeatCounts.size() * 2 && repeatCounts.get(loc) > 3){
70                             repeatCounts.set(loc, repeatCounts.get(loc) - 1);
71                             break;
72                         }
73                     }
74                 }
75             }
76         }
77         
78         //长度满足要求考虑种类要求
79         while(types > 0){
80             if(repeatCounts.size() != 0){
81                 for(int i = 0; i < repeatCounts.size(); i++){
82                     if(repeatCounts.get(i) >= 3){
83                         repeatCounts.set(i, repeatCounts.get(i) - 3);
84                         break;
85                     }
86                 }
87             }
88             types--;
89             steps++;
90         }
91         
92         for(int i = 0; i < repeatCounts.size(); i++){
93             steps += repeatCounts.get(i) / 3;
94         }
95         
96         return steps;
97     }
98 }

 

posted @ 2016-10-22 02:40  zslhq~  阅读(828)  评论(0编辑  收藏  举报