본문 바로가기
Study/알고리즘 문제해결전략(종만북)

[종만북] WILDCARD - Wildcard (자바 java)

by Nahwasa 2023. 4. 2.

알고리즘 문제해결전략(종만북) 스터디 메인 페이지

문제 : aoj-WILDCARD

 

 

풀이

  우선 '*'이 연속으로 있는 경우는 처리만 어렵게 만들고 하나만 있는 경우와 동일하다. 따라서 입력받은 W에서 '*'이 연속으로 있다면 하나로 변경해줬다. 즉, "ab********c" 라면 "ab*c"로 변경해준다.

private String compressContinuousAsterisk(String w) {
    while (w.indexOf("**") != -1) {
        w = w.replace("**", "*");
    }
    return w;
}

 

  그럼 이제 연속된 '*'이 하나로 합쳐진 W와 현재 보고 있는 문자열 cur에 대해 각각 포인터를 두고 움직인다고 해보자. 이 경우 두 개의 포인터가 가르키는 문자열이 동일하거나, W에서 현재 가르키는 문자열이 '?' 라면 둘다 포인터를 움직여줘도 된다.

while (pt1 < w.length() && pt2 < cur.length() && (w.charAt(pt1) == '?' || w.charAt(pt1) == cur.charAt(pt2))) {
    pt1++;
    pt2++;
}

 

  위처럼 진행하다가 멈추는 경우는, W의 끝에 포인터가 도달했거나, W에서 '*'인 문자열을 가르키는 경우이다. 만약 W의 마지막에 '*'이 있었다면 그냥 그대로 가능한 경우이고, W의 끝에 도달했다면 cur도 포인터 끝에 도달했다면 가능한 경우이다. 혹은 현재 W의 포인터가 '*'을 가르키는게 아니라면 cur과 매칭이 안된 것이므로 불가능한 경우이다.

if (pt1 == w.length() - 1 && w.charAt(pt1) == '*') {
    chk = true;
    return;
}

if (pt1 == w.length()) {
    chk = pt2 == cur.length();
    return;
}

if (w.charAt(pt1) != '*')
    return;

 

  그럼 이제 남은 경우는 W에서 맨 끝에 있지 않은 '*'을 가르키고 있는 경우이다. 그렇다면 W에서 그 다음 문자와 매칭되는 모든 위치에서부터 다시 탐색을 진행해주면 된다.

pt1++;	// 다음 문자 보기
int pt1Tmp = pt1;	// 파라미터로 인덱스를 넘기지 않고 있으므로 현재 위치 기억
for (int i = pt2; !chk && i < cur.length(); i++) {

    if (w.charAt(pt1Tmp) == '?' || w.charAt(pt1Tmp) == cur.charAt(i)) {	// 매칭 가능하다면
        pt1 = pt1Tmp;
        pt2 = i;
        match();	// 거기서부터 다시 진행
    }
}

 

 

코드 : github

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

public class Main {

    static BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
    static List<String> ans;
    int pt1, pt2;
    String w, cur;
    boolean chk;

    public static void main(String[] args) throws Exception {
        int c = Integer.parseInt(br.readLine());
        while (c-->0) new Main().solution();
    }

    private void solution() throws Exception {
        String w = br.readLine();
        w = compressContinuousAsterisk(w);
        ans = new ArrayList<>();

        int n = Integer.parseInt(br.readLine());
        while (n-->0) {
            String cur = br.readLine();
            if (isMatch(w, cur))
                ans.add(cur);
        }

        Collections.sort(ans);
        StringBuilder sb = new StringBuilder();
        for (String cur : ans) {
            sb.append(cur).append('\n');
        }
        System.out.print(sb);
    }

    private String compressContinuousAsterisk(String w) {
        while (w.indexOf("**") != -1) {
            w = w.replace("**", "*");
        }
        return w;
    }

    private boolean isMatch(String w, String cur) {
        this.w = w;
        this.cur = cur;
        chk = false;
        pt1 = pt2 = 0;

        match();

        return chk;
    }

    private void match() {

        if (chk) return;

        while (pt1 < w.length() && pt2 < cur.length() && (w.charAt(pt1) == '?' || w.charAt(pt1) == cur.charAt(pt2))) {
            pt1++;
            pt2++;
        }

        if (pt1 == w.length() - 1 && w.charAt(pt1) == '*') {
            chk = true;
            return;
        }

        if (pt1 == w.length()) {
            chk = pt2 == cur.length();
            return;
        }

        if (w.charAt(pt1) != '*')
            return;

        pt1++;
        int pt1Tmp = pt1;
        for (int i = pt2; !chk && i < cur.length(); i++) {

            if (w.charAt(pt1Tmp) == '?' || w.charAt(pt1Tmp) == cur.charAt(i)) {
                pt1 = pt1Tmp;
                pt2 = i;
                match();
            }
        }
    }
}

 

 

※ 종만북에 이미 풀이가 있는데 제 풀이를 올리는 이유는 제가 책의 풀이를 보지 않고 문제를 푼 후 제 풀이를 올리고 나서 책의 풀이를 보는 방식으로 풀어보고 싶기 때문입니다.

댓글