일단 부족한 패턴을 찾는다. 그리고 부족한 패턴을 추가해준다.

만약 길이가 너무 길다면 그 만큼 지운다.

지울 때 지우면 패턴을 맞춰주면서 지워줄 수 있다.

class Solution:
    def strongPasswordChecker(self, s: str) -> int:
        missing = 3
        if any('A'<=c<='Z' for c in s):
            missing -= 1
        if any('a'<=c<='z' for c in s):
            missing -= 1
        if any('0'<=c<='9' for c in s):
            missing -= 1
        
        change = 0
        one = two = 0
        for c,v in itertools.groupby(s):
            l = len(list(v))
            if l >= 3:
                change += l//3
                if l%3 == 0:
										# 만약 aaa 나 aaaaaa 같은 경우라면 1개를 지워주면 change 을 1개 줄여 줄 수 있다.
                    one += 1
                if l%3 == 1:
										# aaaa, aaaaaaa 라면 2개를 지워주면 change 을 1개 줄여줄 수 있다.
                    two += 1
        
				# 위의 과정을 one-pass 로 처리할 수도 있다. 가독성을 위해 일단 따로 처리.
        if len(s) <6:
            return max(missing, 6-len(s))
        if len(s) <= 20:
            return max(change, missing)
        else:
            base_delete = len(s) - 20
            
            delete = base_delete
            
            # delete 1개을 잘 함으로써, change 1개를 줄여줄 수 있다.
            replace = min(delete, one)
            change -= replace
            delete -= replace
            # delete 2개을 잘 함으로써, change 2개를 줄여줄 수 있다.
            if delete >= 0:
                replace = min(delete, two * 2) // 2
                change -= replace
                delete -= replace*2
            if delete >= 0:
								# 연속된 3 개를 다 delete 해버리면 change 1개를 안해도 된다.
                replace = delete // 3
                change -= replace

            return base_delete + max(change, missing)