- 문제 :

https://www.acmicpc.net/problem/2630

 

2630번: 색종이 만들기

첫째 줄에는 전체 종이의 한 변의 길이 N이 주어져 있다. N은 2, 4, 8, 16, 32, 64, 128 중 하나이다. 색종이의 각 가로줄의 정사각형칸들의 색이 윗줄부터 차례로 둘째 줄부터 마지막 줄까지 주어진다.

www.acmicpc.net

- 분류 : 분할정복 알고리즘

 


기본적인 분할정복 알고리즘 문제이다.

 

첨에 2차원 배열을 어떻게 사분할로 쪼개지? 에서 조금 생각을 했는데 결국은 시작점을 상하좌우로 이동시켜서 생각하면 된다. 예를 들면 이렇다.

  //같은 색이 아니라면 1/4로 쪼갠다
int divide = n/2;

int [][] arr1 = new int[divide][divide];
int [][] arr2 = new int[divide][divide];
int [][] arr3 = new int[divide][divide];
int [][] arr4 = new int[divide][divide];


for(int i = 0; i<divide; i++) {
   for(int j = 0; j<divide; j++) {
       arr1[i][j] = arr[i][j];
       arr2[i][j] = arr[i+divide][j];
       arr3[i][j] = arr[i][j+divide];
       arr4[i][j] = arr[i+divide][j+divide];
   }
}

 

풀이

첨에 arr 배열 전체를 넘겨주는 방식으로 풀었는데 다른 사람들의 풀이를 보니 arr[][]을 static으로 두고, index만 넘겨서 푸는 방식으로 풀었길래 나도 그와 같은 방식으로 다시 풀어보았다. 

 

분할정복 알고리즘은 문제를 작은 방식으로 분할하여 해결하는 방식으로, 

이 문제는 "전체 종이 색깔이 같지 않으면 계속 쪼개는(divide)" 방식으로 해결한다. 전체 종이 색깔이 같아질 때 conquer된다.

첫번째 풀이

import java.util.*;

public class Main
{
    static int white = 0;
	static int blue = 0; 
	
	public static void main(String[] args) {
	    Scanner sc = new Scanner(System.in);
	  
	    int n = sc.nextInt();
	    int arr[][] = new int[n][n];
	    
	    for(int i = 0; i<n; i++) {
	        for(int j = 0; j<n; j++) {
	            arr[i][j] = sc.nextInt();
	        }
	        sc.nextLine();
	    }
	   
	    quad(arr);
	    
	    System.out.println(white);
	    System.out.println(blue);
	}
	
	 static void quad(int[][] arr) {
	    int n = arr[0].length;
	    
	    //전체가 같은 색이면 컬러 체크
	    if(n == 1 || isAllColorSame(arr)) {
	        checkColor(arr[0][0]);
	        return;
	    }
	   
        //같은 색이 아니라면 1/4로 쪼갠다
	    int divide = n/2;
	    
        int [][] arr1 = new int[divide][divide];
        int [][] arr2 = new int[divide][divide];
        int [][] arr3 = new int[divide][divide];
        int [][] arr4 = new int[divide][divide];
        
      
	    for(int i = 0; i<divide; i++) {
	       for(int j = 0; j<divide; j++) {
	           arr1[i][j] = arr[i][j];
	           arr2[i][j] = arr[i+divide][j];
	           arr3[i][j] = arr[i][j+divide];
	           arr4[i][j] = arr[i+divide][j+divide];
	       }
	    }
	    
	    quad(arr1);
	    quad(arr2);
	    quad(arr3);
	    quad(arr4);
	}
	
	
	 static boolean isAllColorSame(int[][] arr) {
	    int color = arr[0][0];
	    int n = arr[0].length;
	    
	    //전체가 같은 색인지 체크한다
	    for(int i = 0; i<n; i++) {
	        for(int j = 0; j<n; j++) {
	           if(color != arr[i][j]) {
	               return false;
	           }
	        }
	    }
	    return true;
	}
	
	static void checkColor(int color) {
       if(color == 0) {
            white++;
        } else {
            blue++;
        }
	}
}

 

두번째 풀이

import java.util.*;

public class Main
{
    static int white = 0;
	static int blue = 0; 
	static int arr[][];
	
	public static void main(String[] args) {
	    Scanner sc = new Scanner(System.in);
	  
	    int n = sc.nextInt();
	    arr = new int[n][n];
	    
	    for(int i = 0; i<n; i++) {
	        for(int j = 0; j<n; j++) {
	            arr[i][j] = sc.nextInt();
	        }
	        sc.nextLine();
	    }
	   
	    quad(n, 0, 0);
	    
	    System.out.println(white);
	    System.out.println(blue);
	}
	
	 static void quad(int n, int row, int column) {
	    
	    // 1. 전체가 같은 색이면 컬러 체크
	    if(n == 1 || isAllColorSame(n, row, column)) {
	        checkColor(arr[row][column]);
	        return;
	    }
	   
        // 2. 같은 색이 아니라면 1/4로 쪼갠다
	   int divide = n/2;
	    
       quad(divide, row, column);
       quad(divide, row+divide, column);
       quad(divide, row, column+divide);
       quad(divide, row+divide, column+divide);
	}
	
	
	//전체가 같은 색인지 체크
	 static boolean isAllColorSame(int n, int row, int column) {
	   int color = arr[row][column];
	   
	    for(int i = row; i<n+row; i++) {
	        for(int j = column; j<n+column; j++) {
	           if(color != arr[i][j]) {
	               return false;
	           }
	        }
	    }
	    return true;
	}
	
	static void checkColor(int color) {
       if(color == 0) {
            white++;
        } else {
            blue++;
        }
	}
}

딱 기본적인 stack을 활용한 문제이다.

 


<풀이>

  • 괄호를 만나면 stack에 넣는다.
  • 오른쪽 괄호의 경우 stack의 top에 있는 괄호와 짝을 이룰 경우 stack에 넣지 않고 stack에 들어있는 왼쪽 괄호를 pop한다.
  • 최종적으로 stack이 비어있으면 yes를 출력한다.

 

아래는 java에서 제공하는 Stack을 사용한 풀이이다.

import java.util.Stack;
import java.util.Scanner;

public class BOJ4949 {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);

        while (true) {
            String str = sc.nextLine();
            Stack<Character> stack = new Stack<>();

            if (str.equals("."))
                break;

            for (int i = 0; i < str.length(); i++) {
								// 괄호를 만났을때 
                if (str.charAt(i) == '[' || str.charAt(i) == ']' || str.charAt(i) == '(' || str.charAt(i) == ')') {
										// 넣으려는 괄호가 오른쪽 괄호일 경우는 stack에 왼쪽괄호가 top에 존재할때 stack에서 왼쪽 괄호를 빼낸다
                    if ((!stack.empty() && stack.peek() == '[' && str.charAt(i) == ']') || (!stack.empty() && stack.peek() == '(' && str.charAt(i) == ')')) {
                        stack.pop();
                    } else {
												// 괄호는 스택에 저장한다
                        stack.push(str.charAt(i));
                    }
                }
            }
            System.out.println(stack.isEmpty() ? "yes" : "no");
        }
    }
}

 

아래는 ArrayList를 이용해서 직접 Stack을 구현해서 푼 풀이이다.

import java.util.*;

/*
백준 4949번 균형잡힌 세상
분류 : stack
직접 스택 구현해서 풀기
* */


public class BOJ4949_2 {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);

        while (true) {
            String str = scanner.nextLine();
            Stack stack = new Stack();
            if (str.equals("."))
                break;

            for (int i = 0; i < str.length(); i++) {
                if (str.charAt(i) == '[' || str.charAt(i) == ']' || str.charAt(i) == '(' || str.charAt(i) == ')') {
                    if ((!stack.isEmpty() && stack.peek() == '[' && str.charAt(i) == ']') || (!stack.isEmpty() && stack.peek() == '(' && str.charAt(i) == ')')) {
                        stack.pop();
                    } else {
                        stack.push(str.charAt(i));
                    }
                }
            }
            System.out.println(stack.isEmpty() ? "yes" : "no");
        }
    }

    private static class Stack {
        private List<Character> elements;
        private int elementSize;

        public Stack() {
            this.elements = new ArrayList<>();
            this.elementSize = 0;
        }

        public void push(char element) {
            elements.add(element);
            elementSize++;
        }

        public void pop() {
            if (isEmpty()) {
                throw new EmptyStackException();
            }

            elements.remove(elementSize - 1);
            elementSize--;
        }

        public char peek() {
            if (isEmpty()) {
                throw new EmptyStackException();
            }

            return elements.get(elementSize - 1);
        }

        public boolean isEmpty() {
            if (elementSize == 0) {
                return true;
            }
            return false;
        }


    }
}
 

9095번: 1, 2, 3 더하기

각 테스트 케이스마다, n을 1, 2, 3의 합으로 나타내는 방법의 수를 출력한다.

www.acmicpc.net

 


풀이

  • n은 양수이며 11미만이다. 그러므로 DP테이블의 사이즈를 11로 하였다. (인덱스0은 비워둠)
  • n이 4일때를 계산해보면 쉽게 점화식을 구할 수 있다.
    • n=1 → 1
    • n=2 → 2 (1+1, 2)
    • n=3 → 4 (2+1, 1+2, 1+1+1, 3)
    • n=4 → 7 (1+1+1+1, 2+2, 2+1+1, 1+2+1, 1+1+2, 3+1, 1+3)

 

import java.util.Scanner;

/*
* 분류 : DP
* */
public class BOJ9095 {
    static int[] table = new int[11];

    public static void main(String[] args) {
        table[1] = 1;
        table[2] = 2; // 1+1, 2
        table[3] = 4; // 2+1, 1+2, 1+1+1, 3
//        table[4] = 7; // 1+1+1+1, 2+2, 2+1+1, 1+2+1, 1+1+2, 3+1, 1+3

        Scanner sc = new Scanner(System.in);
        int n = sc.nextInt();
        int[] nn = new int[n];
        for (int i = 0; i < n; i++) {
            nn[i] = sc.nextInt();
        }

        for (int i = 0; i < n; i++) {
            System.out.println(recur(nn[i]));
        }
    }

    public static int recur(int n) {
        if (n < 4 || table[n] > 0) {
            return table[n];
        }

        return table[n] = recur(n - 1) + recur(n - 2) + recur(n - 3);
    }
}

문제

https://school.programmers.co.kr/learn/courses/30/lessons/17680

 

프로그래머스

코드 중심의 개발자 채용. 스택 기반의 포지션 매칭. 프로그래머스의 개발자 맞춤형 프로필을 등록하고, 나와 기술 궁합이 잘 맞는 기업들을 매칭 받으세요.

programmers.co.kr

 

풀면서 재밌었던 문제이다.

 

LRU (Least Recently Used) 알고리즘

Least Recently Used (LRU) is a common caching strategy. It defines the policy to evict elements from the cache to make room for new elements when the cache is full, meaning it discards the least recently used items first.
  • OS의 페이지 교체 알고리즘 중 하나.
  • 문제에 언급된 LRU 알고리즘은 보편적인 캐싱 전략이며, 캐시가 다 찼을 때 새로운 값을 넣기 위해 가장 오랫동안 사용되지 않은 것을 버리는 방식이다.
  • cache hit : CPU가 참조하고자 하는 메모리가 캐시에 존재하고 있는 경우.
  • cache miss : CPU가 참조하고자 하는 메모리가 캐시에 존재하지 않는 경우.

 

아래 이미지를 통해 LRU알고리즘의 동작방식을 살펴보겠다.  0, 1, 2, 3, 0, 1, 4, 0, 1, 2, 3, 4 가 주어지고, cache size는 3이다. 빨간색 부분이 교체되는 가장 오랫동안 참조되지 않은 페이지이고, 노란 부분이 제일 최근에 참조된 페이지이다. 

출처 :&nbsp;https://www.educative.io/answers/what-is-the-least-recently-used-page-replacement-algorithm

  • java에서 Doubly Linked List를 이용해서 구현할 수 있다.
    • 사용이유 : list의 front(head)나 end(tail)에 접근시에 모두 O(1) 상수시간 내에 접근 가능하기 때문이다. 그리고 insert, delete시에도 상수시간이다.

 


풀이

처음엔 '가장 오랫동안 참조되지 않은 페이지'를 찾으려면 어떻게 해야하지? 싶어서 LinkedHashMap을 이용해서 value에 참조된 횟수를 저장하는 식으로 풀려고 했다. 그런데 최근 참조된 페이지를 head에 두고, 오랫동안 참조되지 않은 페이지를 tail에 두는 식으로 풀면 굳이 몇번 참조되었는지의 상세한 정보는 필요가 없어서 LinkedHashSet을 이용해서 푸는 풀이로 바꿨다.

 

LinkedHashSet을 이용하면 값의 중복은 비허용하고, 삽입한 순서를 기억하기 때문에 아래 방식으로 풀었다.

  1. hit한 경우에는 element를 remove했다가 다시 insert해준다. => 최신값으로 유지. 
  2. 가장 오랫동안 참조되지 않은 element는 맨 앞에 남게 된다.

전체코드

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
import java.util.*;
 
 
class Solution {
    public int solution(int cacheSize, String[] cities) {
        int answer = 0;
        final int HIT = 1;
        final int PASS = 5;
 
        Set<String> hashSet = new LinkedHashSet<String>(cacheSize);
 
        for (String city : cities) {
            // 대소문자 구분 안하므로
            String c = city.toLowerCase();
 
            if (hashSet.isEmpty()) {
                hashSet.add(c);
                answer += PASS;
            } else {
                // 가장 오래 참조되지 않은 값을 제거
                if (cacheSize < hashSet.size()) {
                    hashSet.remove(hashSet.stream().findFirst().get());
                }
                //hit (hit하면 맨 뒤로 보내줘서 최신으로 만든다)
                if (hashSet.contains(c)) {
                    hashSet.remove(c);
                    hashSet.add(c);
                    answer += HIT;
                }
                //pass
                else {
                    hashSet.add(c);
                    answer += PASS;
                }
            }
        }
        return answer;
    }
}
cs

 

 

 

 

 


 

참고자료

https://velog.io/@haero_kim/LRU-Cache-%EC%9D%B4%ED%95%B4%ED%95%98%EA%B8%B0

 

LRU Cache 이해하기

상당히 유용하게 사용되는 LRU 캐싱 이해하기

velog.io

 

- 문제 : https://www.acmicpc.net/problem/2805

 

2805번: 나무 자르기

첫째 줄에 나무의 수 N과 상근이가 집으로 가져가려고 하는 나무의 길이 M이 주어진다. (1 ≤ N ≤ 1,000,000, 1 ≤ M ≤ 2,000,000,000) 둘째 줄에는 나무의 높이가 주어진다. 나무의 높이의 합은 항상 M보

www.acmicpc.net

- 분류 : 이분탐색

 

이분탐색 (Binary Search)

이분탐색 알고리즘은 linear search에서 업그레이드된 방식으로, 정렬된 리스트를 반으로 나눠서 반복 탐색하는 방식이다.

계속 탐색범위를 반으로 나누므로 시간복잡도는 O(logN)이다.

 


백준2805번 나무자르기 풀이

  • 나무의 높이의 합은 항상 M보다 크거나 같기 때문에, 상근이는 집에 필요한 나무를 항상 가져갈 수 있다. => 상근이가 나무를 집에 가져가지 못할 경우는 없다. (즉 탐색했을 경우 찾는 값이 없는 경우는 없다)
    • if(first > last) return null;  not found 인 경우는 없다.
  • 나무의 높이는 1,000,000,000보다 작거나 같은 양의 정수 또는 0이다 => 져갈 나무의 높이의 합을 구할 때 int 범위를 초과할 수 있으므로 result는 long타입으로 설정한다. 
    • int형 저장범위 : -2,147,483,648 ~ 2,147,483,647
  • 높이가 H보다 큰 나무는 H 위의 부분이 잘릴 것이고, 낮은 나무는 잘리지 않을 것이다. => (나무의 높이 - h)가 음수인 경우는 잘리지 않기 때문에 result에 더하지 않는다
  • 0부터 최대 나무의 높이를 범위로 두고, 이분탐색으로 절단기에 설정할 수 있는 높이의 최댓값을 구한다.
    • 만약 result < m 이면 더 잘라야하므로 왼쪽 범위를 탐색한다 (좀더 자르려면 절단기의 높이가 낮아져야 한다)
    • result > m 이면 덜 잘라야하므로 오른쪽 범위를 탐색한다 (좀덜 자르려면 절단기의 높이를 높혀야 한다)

나무자르기 예제

import java.util.Arrays;
import java.util.Scanner;

public class BOJ2805 {

    static int[] trees;

    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);

        int n = sc.nextInt();
        int m = sc.nextInt();
        sc.nextLine();
        trees = new int[n];
        for (int i = 0; i < n; i++) {
            trees[i] = sc.nextInt();
        }

        int first = 0;
        int last = Arrays.stream(trees).max().getAsInt(); //최대 높이의 나무
        int middle = (last + first) / 2;
        long result = findResult(middle);

        while (first <= last) {
            if (result < m) {
                // 더 조금 잘라야 하니 왼쪽으로
                last = middle - 1;
            } else {
                // 더 많이 잘라야 하니 오른쪽으로
                first = middle + 1;
            } 

            middle = (last + first) / 2;
            result = findResult(middle);
        }
        System.out.println(middle);
    }

    public static long findResult(int h) {
        long result = 0;
        for (int tree : trees) {
            //음수인 경우는 더하지 않는다
            result += (Math.max((tree - h), 0));
        }
        return result;
    }
}

 

 


나무자르기 테스트케이스

1 1
1000000000
output : 999999999

5 100
99 1 1 1 1
output : 0

 

  • 문제 : https://www.acmicpc.net/problem/17609
  • 분류 : 투포인터 
  • 시간초과를 해결하기 위해 check가 2 이상인 경우는 바로 2를 리턴해준다. 이미 회문, 유사회문이 아닌 것으로 판정났으니 더이상 재귀함수를 호출하지 않도록.
  • 풀이방법 : 투포인터로 문자열의 맨앞부터 시작, 문자열의 맨뒤부터 시작해서 서로 비교한다. 만약 서로 다른 구간이 발생하면 그 앞뒤로 비교하도록 하고, 만약 앞뒤로 비교했을 때 회문으로 충족된다면 유사회문으로 볼 수 있다.
package boj.string;

import java.io.BufferedReader;
import java.io.InputStreamReader;

/**
 * @문제명 회문
 * @분류 투포인터, 문자열
 */
public class BOJ17609 {
    public static void main(String[] args) throws Exception {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        int n = Integer.parseInt(br.readLine());

        String[] arr = new String[n];
        for (int i = 0; i < n; i++) {
            arr[i] = br.readLine();
        }

        for (int i = 0; i < n; i++) {
            String current = arr[i];
            System.out.println(palindrome(0, current.length() - 1, current, 0));
        }
    }

    private static int palindrome(int s, int e, String s1, int check) {
        // 시간초과를 해결하기 위해 아래 조건을 추가함
        if(check >=2) return 2;

        while (s < e) {
            if (s1.charAt(s) == s1.charAt(e)) {
                s++;
                e--;
            } else {
                return Math.min(palindrome(s + 1, e, s1, check + 1), palindrome(s, e - 1, s1, check + 1));
            }
        }
        return check;
    }
}

<ul style="list-style-type: disc;" data-ke-list-type="disc">
<li>분류 : 완전탐색, 재귀</li>
<li>풀이</li>
</ul>
<p>

</p>
<pre id="code_1682592342876" class="java" data-ke-language="java" data-ke-type="codeblock"><code>import java.util.Arrays;
import java.util.Scanner;

public class Main {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        int n = sc.nextInt();
        int count = sc.nextInt();
        sc.nextLine();
        int[] k = new int[count];
        for (int i = 0; i &lt; count; i++) {
            k[i] = sc.nextInt();
        }

        Arrays.sort(k);

        int result = find_max(n, k, 0);
        System.out.println(result);

    }

    private static int find_max(int n, int[] k, int currentMax) {
        if(currentMax &gt; n) return 0;
        int max = currentMax;
        for (int i = k.length - 1; i &gt;= 0; i--) {
            int tmp = currentMax * 10 + k[i];
            max = Math.max(max, find_max(n, k, tmp));
        }
        return max;
    }
}</code></pre>

https://www.acmicpc.net/problem/3085

 

3085번: 사탕 게임

예제 3의 경우 4번 행의 Y와 C를 바꾸면 사탕 네 개를 먹을 수 있다.

www.acmicpc.net

  • 분류 : 완전탐색

 

 

처음에 풀고나서 다른 사람들 풀이를 보고 기존에 제출했던 내 코드를 많이 뜯어고쳤다.

아래는 내가 처음 제출한 코드이다.

 

첫번째 풀이

  • 반복문을 돌면서 swap()메서드로 인접한 사탕 위치(상하좌우)를 서로 바꿔서 clone된(swap된 배열) 배열을 리턴해준다. 그리고 그 swap된 배열을 countMaxCandyCount() 메서드로 행과 열을 체크하여 각 행과 열에 최대 사탕 개수를 찾는다.
import java.util.Scanner;

public class BOJ3085 {
    static char[][] arr;
    static int n;

    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        n = sc.nextInt(); //  (3 ≤ N ≤ 50)
        sc.nextLine();
        arr = new char[n][n];
        for (int i = 0; i < n; i++) {
            String s = sc.nextLine();
            for (int j = 0; j < s.length(); j++) {
                arr[i][j] = s.charAt(j);
            }
        }
        findMax();
    }

    static private void findMax() {
        int max = 0;
        for (int i = 0; i < n; i++) {
            for (int j = 0; j < n; j++) {
                //인접한 사탕 swap
                max = Math.max(countMaxCandyCount(swap(i, j, i, j - 1)), max);
                max = Math.max(countMaxCandyCount(swap(i, j, i, j + 1)), max);
                max = Math.max(countMaxCandyCount(swap(i, j, i + 1, j)), max);
                max = Math.max(countMaxCandyCount(swap(i, j, i - 1, j)), max);

            }
        }
        System.out.println(max);
    }

    static int countMaxCandyCount(char[][] clone) {
        if (clone == null) return -1;
        int max = 0;
        // row 체크
        for (int i = 0; i < n; i++) {
            int count = 1;
            for (int j = 0; j < n - 1; j++) {
                if (clone[i][j] == clone[i][j + 1]) count++;
                else count = 1;
                max = Math.max(max, count);
            }
        }

        // column 체크
        for (int i = 0; i < n; i++) {
            int count = 1;
            for (int j = 0; j < n-1; j++) {
                if (clone[j][i] == clone[j + 1][i]) count++;
                else count = 1;
                max = Math.max(max, count);
            }
        }
        return max;
    }

    static private char[][] swap(int i, int j, int a, int b) {
				//가장자리라서 상하좌우 위치가 유효하지 않은 경우
        if (a < 0 || a > n - 1 || b < 0 || b > n - 1) {
            return null;
        }
        // deep copy
        char[][] clone = new char[n][n];
        for(int x = 0; x<n; x++) {
            clone[x] = arr[x].clone();
        }

			  //swap 
        char tmp = clone[i][j];
        clone[i][j] = clone[a][b];
        clone[a][b] = tmp;

        return clone;
    }
}

 

수정한 코드

코드가 좀 지저분함을 스스로 느꼈다. 일단 굳이 swap한 배열을 clone해야하나? 싶기도 했고, 여러모로 리팩토링이 필요했다. 다른 사람들의 풀이를 참고해서 기존 코드를 아래와 같이 수정했다.

 

1. 상하좌우를 전체 다 swap하지 않고, 오른쪽과 아래쪽 값하고만 swap하도록 한다.

  • 중복되는 swap 횟수를 줄였다. 어차피 arr[i][j-1]가 오른쪽에 있는 arr[i][j]와 swap하는 것과 arr[i][j]가 왼쪽에 있는 arr[i][j-1]와 swap하는게 동일하기 때문이다. 

2. swap할 때 굳이 deep copy를 해서 배열을 리턴하기보다는, swap 후 다시 원상복구해서 돌려놓는다. 그러면 매개변수로 굳이 배열을 넘길 필요가 없다.

  • 위에서 언급했던 배열을 copy하는 부분을 제거했다. 배열을 복사하지 않고 swap후에 다시 되돌려놓으면(다시 swap해주면) 굳이 copy할 필요가 없기 때문이다.
import java.util.Scanner;

public class BOJ3085 {
    static char[][] arr;
    static int n;

    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        n = sc.nextInt(); //  (3 ≤ N ≤ 50)
        sc.nextLine();
        arr = new char[n][n];
        for (int i = 0; i < n; i++) {
            String s = sc.nextLine();
            for (int j = 0; j < s.length(); j++) {
                arr[i][j] = s.charAt(j);
            }
        }
        findMax();
    }

    static private void findMax() {
        int max = 0;
        for (int i = 0; i < n; i++) {
            for (int j = 0; j < n - 1; j++) {
                // 인접한 사탕(오른쪽과 아래쪽) swap
                swap(i, j, i, j + 1);
                max = Math.max(findMaxCandyCount(), max);
                swap(i, j + 1, i, j); //swap했던걸 돌려놓음
            }
        }

        for (int i = 0; i < n - 1; i++) {
            for (int j = 0; j < n; j++) {
                swap(i, j, i + 1, j);
                max = Math.max(findMaxCandyCount(), max);
                swap(i + 1, j, i, j);
            }
        }
        System.out.println(max);
    }

    static int findMaxCandyCount() {
        int max = 0;
        for (int i = 0; i < n; i++) {
            // row 체크
            int count = 1;
            for (int j = 0; j < n - 1; j++) {
                if (arr[i][j] == arr[i][j + 1]) count++;
                else count = 1;
                max = Math.max(max, count);
            }

            // column 체크
            count = 1;
            for (int j = 0; j < n - 1; j++) {
                if (arr[j][i] == arr[j + 1][i]) count++;
                else count = 1;
                max = Math.max(max, count);
            }
        }
        return max;
    }

    static private void swap(int i, int j, int a, int b) {
        char tmp = arr[i][j];
        arr[i][j] = arr[a][b];
        arr[a][b] = tmp;
    }
}

+ Recent posts