

이 문제는 먼저 제품과 개수가 하나로 묶여야 한다. 먼저 HashMap을 이용하여 제품과 개수를 하나로 묶는다.
discount의 값을 순서대로 꺼내어 다음을 실행한다.
해당 값이 맵에 존재하지 않으면 다음으로 넘어간다.
해당 값이 맵에 존재하면 해당 값의 value에서 1을 뺀다.
11번째 값부터는 10번째 전의 값을 다시 가져온다.
만약 해당 값이 맵에 존재한다면 해당 값의 value에 1을 더한다.
모든 해시맵의 값을 더했을 때 정확히 0이 나오면 자신이 원하는 제품과 수량이 할인하는 날짜와 10일 연속으로 일치하는 것이므로 answer에 1을 더한다.
import java.util.*;
class Solution {
Integer MEMBER_DAY = 10;
public int solution(String[] want, int[] number, String[] discount) {
Map<String, Integer> products = combineProductsAndNumber(want, number);
return countCorrectProducts(products, discount);
}
// 제품과 개수 묶기
private Map<String, Integer> combineProductsAndNumber (String[] want, int[] number) {
Map<String, Integer> products = new HashMap<>();
for (int i = 0; i < want.length; i ++) {
products.put(want[i], number[i]);
}
return products;
}
// 원하는 제품과 수량이 할인하는 날짜와 10일 연속으로 일치하는 개수 찾기
private int countCorrectProducts (Map<String, Integer> products, String[] discount) {
int cnt = 0;
for (int day = 0; day < discount.length; day ++) {
productNumChangeInWant(products, discount, day);
System.out.println("day: " + day + " " + products);
if (isMemberSatisfied(products)) {
cnt ++;
}
}
return cnt;
}
// 할인 상품이 want에 있는 상품만 상태 변경
private void productNumChangeInWant (Map<String, Integer> products, String[] discount, int day) {
if (checkDiscountInWant(products, discount[day])) {
processProductBasedOnDay(products, discount, day);
}
}
// 상품 처리 로직 분리
private void processProductBasedOnDay(Map<String, Integer> products, String[] discount, int day) {
if (day >= MEMBER_DAY) {
NumChangeOfDiscountProductBefore10Day(products, discount[day-MEMBER_DAY]);
}
minus1ToProduct(products, discount[day]);
}
// 할인 품목이 want에 있는지 확인
private boolean checkDiscountInWant (Map<String, Integer> products, String discount) {
return products.containsKey(discount);
}
// 10일 전 할인 상품이 want에 있는 상품만 상태 변경
private void NumChangeOfDiscountProductBefore10Day (Map<String, Integer> products, String discount) {
if (checkDiscountInWant(products, discount)) {
plus1ToProduct(products, discount);
}
}
// 해시 value에 1 더하기
private Map<String, Integer> plus1ToProduct (Map<String, Integer> products, String product) {
products.put(product, products.getOrDefault(product, 0) + 1);
return products;
}
// 해시 value에 1 빼기
private Map<String, Integer> minus1ToProduct (Map<String, Integer> products, String product) {
products.put(product, products.getOrDefault(product, 0) - 1);
return products;
}
// 회원 등록 가능한지 확인
private boolean isMemberSatisfied(Map<String, Integer> products) {
return products.values().stream().allMatch(v -> v == 0);
}
}

정확한 반례나 원인은 찾지 못하였다. 하지만 앞에서부터 하나씩 상태를 변경시키는 과정에서 10일 이후부터는 더하는 로직과 빼는 로직이 함께 실행되기 때문에 상태가 왜곡될 수 있는 것 같다.
할인 품목을 10개씩 잘라서 독립적으로 확인하는 방식을 생각해 보았다.
1일차부터 순서대로 10일씩 자른다. 10일이 유지가 되어야 하기 때문에 (discount의 길이 - 10 일차)까지 순서대로 10일씩 자른다. 자른 배열은 개수를 세기 쉽도록 List로 변경한다.
want 배열의 값을 하나씩 꺼내면서 List에 있는 개수와 number가 동일한지 확인한다.
동일하지 않다면 다음 반복문으로 넘어간다.
동일하다면 answer에 1을 더해준다.
import java.util.*;
import java.util.stream.*;
class Solution {
Integer MEMBER_DAY = 10;
public int solution(String[] want, int[] number, String[] discount) {
int answer = 0;
for (int i = 0; i <= discount.length - MEMBER_DAY; i ++) {
List<String> discounting = Arrays.asList(cutDiscount(discount, i));
boolean canMember = true;
for (int j = 0; j < want.length; j ++) {
int discountNum = Collections.frequency(discounting, want[j]);
if (discountNum != number[j]) {
canMember = false;
break;
}
}
if (canMember) {
answer ++;
}
}
return answer;
}
// 10일로 자르기
private String[] cutDiscount (String[] discount, int firstDay) {
return Arrays.copyOfRange(discount, firstDay , firstDay + MEMBER_DAY);
}
}
독립적으로 진행하니 쉽게 성공하였다...

동시성 문제가 생길 수 있음을 인지하고 코드를 짜는 것이 중요하다는 것을 느꼈다.
그리고 기능마다 함수를 분리하는 것은 너무 어렵다...