import java.util.HashMap;

public class Solution {
	
	public static int[] solution(int[][] orders) {
		int[] answer = {};
		int studentCnt = orders.length; // 5
		int tempCnt = 0; // 후보의 현재 특표 수를 담을 임시 변수
        
		HashMap<Integer, Integer> nomineeHm; // 후보 번호 : 득표 수 담을 해시맵
		HashMap<Integer, Integer> dropHm = new HashMap<>(); // 탈락한 후보 번호 담을 해시맵
        
		int halfNum = 0; // 반수
        
		answer = new int[2]; // 회차, 후보 번호
        
		if (studentCnt % 2 == 0) {
			halfNum = studentCnt / 2; // 짝수일 경우 반수는 (학생 수 / 2)
		} else {
			halfNum = (studentCnt + 1) / 2; // 홀수일 경우 반수는 ((학생 수 + 1) / 2)
		}
        
		int checkCnt = 0; // 선거 카운트
        
		int rowNum = 0; // 탈락한 학생을 제외한 0순위 후보를 가져오기 위한 변수 (0부터 증가하며 체크)
        
		for (int j = 0; j < studentCnt; j++) { // 선거 회수 증가를 위한 반복문
        	
			nomineeHm = new HashMap<>();
        	
			for (int k = 0; k < studentCnt; k++) {
        		
				if (dropHm.get(k) != null) continue; // 후보에서 탈락한 학생이 있다면 그 학생을 제외하고 후보 등록
        		
				nomineeHm.put(k, 0); // 후보 등록 // 표를 얻지 못했더라도, 탈락된 후보가 아니라면 이번 회차의 당선 또는 탈락의 대상이 됨
			}
        	
			for (int i = 0; i < studentCnt; i++) { // 행
        		
				rowNum = 0; // 0순위 후보
        		
				while (dropHm.get(orders[i][rowNum]) != null) { // 0순위 후보가 탈락한 학생이라면 그 다음 순위 학생 체크 (탈락하지 않은 최대 우선 순위까지 체크)
					rowNum++;
					if (rowNum > studentCnt - 1) break;
				}
        		
				tempCnt = nomineeHm.get(orders[i][rowNum]);
				nomineeHm.put(orders[i][rowNum], tempCnt + 1); // 후보의 득표 수 증가
			}
        	
			checkCnt++; // 선거 카운트 증가
        	
			int[] dropNum = new int[2]; // 이번 회차에서 탈락할 후보의 번호, 득표 수를 담을 배열
        	
			dropNum[1] = studentCnt; // 5
        	
			for (int i = 0; i < studentCnt; i++) {
        		
				if (nomineeHm.get(i) == null) { // 이미 탈락한 후보라면 continue
					continue;
				} else { // 정상 후보라면
        			
					if (nomineeHm.get(i) >= halfNum) { // 반수를 넘었다면 최종 당선 후보(단, 반수를 넘은 학생이 2명 이상일 경우 후보 번호가 큰 학생이 당선 => 작은 번호부터 체크하기 때문에 이후에 반수를 넘은 다른 학생이 있다면 최종 당선 후보 변경)
						answer[0] = checkCnt; // 최종 선거 회차 담기
						answer[1] = i; // 당선 후보 번호 담기
					} else {
        				
						if (nomineeHm.get(i) < dropNum[1]) { // 현재 후보보다 득표 수가 적다면 탈락 후보 변경
							dropNum[0] = i;
							dropNum[1] = nomineeHm.get(i);
						}
					}
				}
			}
        	
			if (answer[0] == checkCnt) { // 최종 선거 회차가 담겼다면
				System.out.println(answer[0] + " " + answer[1]);
				return answer; // 선거 회차, 당선 번호 리턴
			}
        	
			dropHm.put(dropNum[0], 1); // 탈락한 후보의 번호 담기
		}
        
		return answer;
	}

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		int[][] orders = {{2,3,4,0,1}, {1,4,3,2,0}, {4,1,0,2,3}, {3,2,1,4,0}, {0,3,2,1,4}}; // 4, 3
//		int[][] orders = {{2,1,0,3}, {3,2,0,1}, {3,0,2,1}, {2,3,0,1}}; // 1, 3
//		int[][] orders = {{2,1,0,3,4}, {4,2,0,1,3}, {3,0,4,2,1}, {2,4,3,0,1}, {4,1,3,2,0}}; // 4, 4 // {{2,1,3,4}, {4,2,1,3}, {3,4,2,1}, {2,4,3,1}, {4,1,3,2}} // 1차에 0 탈락 // {{2,3,4}, {4,2,3}, {3,4,2}, {2,4,3}, {4,3,2}} // 2차에 1 탈락 // {{2,4}, {4,2}, {4,2}, {2,4}, {4,2}} // 3차에 3 탈락 // 4차에 4 당선
		
		System.out.println(solution(orders));
	}
}

선거 회차 수가 증가할 때마다 탈락 또는 당선이 결정된다.

득표 수가 반수를 넘은 학생이 있다면 그 학생이 당선 후보가 되며, 반수를 넘은 학생이 2명 이상일 경우

번호가 더 뒤인 학생이 당선되는 룰을 따른다. 당선자가 결정되면 선거를 종료한다.

 

★이미 탈락한 후보가 아니라면, 표를 얻지 못했을 경우에도 이번 선거의 후보이며,

득표 수를 0으로 체크해야 한다는 점을 놓치면 안된다.★

 

프로그래머스 자비스앤빌런즈 2022 코딩테스트 선거 문제 풀이 Java

import java.util.LinkedList;
import java.util.Queue;

public class Solution {
	
	// 올바른 괄호
	
	static boolean solution(String s) {
		boolean answer = true;
		char tempChar;
        
		Queue<Character> q = new LinkedList<>();
        
		for (int i = 0; i < s.length(); i++) {
			
			tempChar = s.charAt(i);
			
			if (tempChar == '(') { // '('라면
				
				q.offer(tempChar); // 큐에 넣기
				
			} else { // ')'라면
        		
				if (q.isEmpty()) { // 이 시점에 큐가 비어있는 상태라면 짝이 맞지 않는 것이므로 answer = false 후 break
					answer = false;
					break;
				}
        		
				q.poll(); // 큐에 있는 '(' 괄호 꺼내기
			}
		}
        
		if (!q.isEmpty()) { // 짝이 맞았다면 '(' 괄호가 모두 제거되었어야 한다. 큐가 비어있는 상태가 아니라는 것은 짝이 맞지 않았다는 뜻이므로 answer = false
			answer = false;
		}
        
		return answer;
	}

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		String s = "(())()";
		
		System.out.println(solution(s));
	}
}

 

큐 자료구조를 이용해 문제를 풀면 쉽게 풀리는 문제

 

프로그래머스 올바른 괄호 문제 풀이 Java

import java.util.Arrays;

public class Solution {
	
	// 구명보트
	
	public static int solution(int[] people, int limit) {
		int answer = 0;
		
		Arrays.sort(people); // 50, 50, 70, 80
		
		int maxWeightIndex = people.length - 1; // 구조되지 않은 사람 중 가장 무거운 무게를 가진 사람의 인덱스
		int minWeightIndex = 0; // 구조되지 않은 사람 중 가장 가벼운 무게를 가진 사람의 인덱스
		
		for (int i = maxWeightIndex; i >= 0; i--) { // 구조되지 않은 사람 중 가장 무거운 무게를 가진 사람부터 순서대로 구조
			
			answer++; // 보트에 타지 못하는 경우는 없으므로 1 증가 // 구조되지 않은 사람 중 가장 무거운 무게를 가진 사람 무조건 보트에 태우기
			
			if (i == minWeightIndex) { // max 인덱스 감소 후 min 인덱스와 값이 같다는 것은 해당 위치에 혼자 남은 경우를 의미하며 위에서 구조 보트에 이미 탔기 때문에(answer증가) 바로 break
				break;
			}
			
			if (people[i] + people[minWeightIndex] <= limit) { // 보트에는 최대 2명까지 탈 수 있고 구조되지 않은 사람 중 가장 무거운 무게를 가진 사람이 탄 보트에 현재 가장 가벼운 사람 또한 함께 탈 수 있다면
				minWeightIndex++; // 현재 가장 가벼운 사람도 함께 구조된 것으로 간주하고 min 인덱스 1 증가 => 다음 가벼운 사람에게 순서를 넘김
			}
			
			if (i == minWeightIndex) { // min 인덱스 증가 후 max 인덱스와 값이 같다면 모든 인원에 대해 구조가 끝난 상황이므로 바로 break
				break;
			}
			
//			if (i <= minWeightIndex) { // 위에 break if문 2개를 모두 주석처리 하고 이 if문만 살려도 결과는 같다.
//				break;
//			}
		}
		
		return answer;
	}

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		int[] people = {70, 50, 80, 50};
		int limit = 100;
		
		System.out.println(solution(people, limit));
	}
}

프로그래머스 구명보트 문제 풀이 Java

import java.util.ArrayDeque;
import java.util.Deque;

public class Solution {
	
	// 행렬과 연산
	// Deque 자료구조에서
	// add(A) + peek(B) or remove(B)가 있을 때 // (A)와 (B)는 First 또는 Last
	// (A)와 (B)가 같다면 스택(Stack)처럼 동작
	// (A)와 (B)가 다르다면 큐(Queue)처럼 동작
	// addFirst로 쌓고 있는 구조에서 제일 앞에 원소를 추가하고 싶다면 addLast로 추가
	// addLast로 쌓고 있는 구조에서 제일 앞에 원소를 추가하고 싶다면 addFirst로 추가
	
	static int r = 0; // rc의 행 수
	static int c = 0; // rc의 열 수
	static Deque<Integer> firstCol; // rc의 1열
	static Deque<Integer> lastCol; // rc의 마지막열
	static Deque<Deque<Integer>> restRows; // rc의 1열, 마지막열을 제외한 나머지 행들
	
	// 2차원 배열을 2개의 열과 나머지 행 구조로 나누기
	public static void rcSetting(int[][] rc) {
		r = rc.length; // 행
		c = rc[0].length; // 열
		firstCol = new ArrayDeque<Integer>(); // 1열
		lastCol = new ArrayDeque<Integer>(); // 마지막열
		restRows = new ArrayDeque<Deque<Integer>>(); // 나머지 행
		
//		1 2 3
//		4 5 6
//		7 8 9
		
//		2차원 배열이 위와 같다면
//		r = 3, c = 3
//		firstCol = {1, 4, 7}
//		lastCol = {3, 6, 9}
//		restRows = {2, 5, 8}
		
		// 상단, 좌측부터 addFirst로 넣을 거야
		// 모두 addFirst로 넣는다는 것을 기억
		for (int i = 0; i < r; i++) {
			firstCol.addFirst(rc[i][0]); // 1열 담기
			lastCol.addFirst(rc[i][c - 1]); // 마지막열 담기
			
			 Deque<Integer> tempRow = new ArrayDeque<Integer>(); // restRows에 담을 tempRow 생성
			 
			 for (int j = 1; j < c - 1; j++) { // 1열과 마지막열을 제외한 모든 열의 원소 담기
				 tempRow.addFirst(rc[i][j]);
			 }
			 
			 restRows.addFirst(tempRow); // tempRow 담기
		}
	}
	
	// 테두리 한 칸씩 시계방향 회전
	public static void rotate() {
		
		if (c == 2) { // firstCol, lastCol만으로 이루어진 2차원 배열
			lastCol.addLast(firstCol.removeLast());
			// firstCol의 제일 처음에 들어왔던 원소가 빠져나가야 함 => addFirst에서 Queue 구조로 빠져나가려면 removeLast로 빼내야 한다.
			// 빼낸 값을 lastCol의 addFirst로 제일 처음 들어왔던 원소보다 앞에 넣어야 하므로 addLast로 넣어준다.
			
			firstCol.addFirst(lastCol.removeFirst());
			// lastCol의 제일 마지막에 들어왔던 원소가 빠져나가야 함 => addFirst에서 Stack 구조로 빠져나가려면 removeFirst로 빼내야 한다.
			// 빼낸 값을 firstCol의 addFirst로 가장 마지막에 들어왔던 원소의 뒤에 넣어야 하므로 똑같이 addFirst로 넣어준다.
			
			return;
		}
		
		// 테두리에 원소 추가할 순서는 상, 우, 하, 좌 순서로 하겠다.
		restRows.peekLast().addLast(firstCol.removeLast()); // 1열(firstCol)의 처음 들어온 원소를 빼냄(addFirst에서 Queue 구조로 쓰기 위해 removeLast) => restRows의 처음 들어온 행을 기준으로 잡아야 함(Queue 구조로 쓰기 위해 peekLast) => 행의 원소 중 처음에 들어왔던 원소보다 앞에 넣어줘야 하므로 addLast
		lastCol.addLast(restRows.peekLast().removeFirst()); // restRows의 처음 들어온 행 중 마지막 원소를 빼내어 마지막 열 제일 앞에 끼어들기해서 추가
		restRows.peekFirst().addFirst(lastCol.removeFirst()); // 마지막 열의 제일 마지막에 들어온 원소를 빼내어 restRows의 가장 마지막에 들어온 행 중 가장 마지막에 들어온 원소 뒤에 추가
		firstCol.addFirst(restRows.peekFirst().removeLast()); // restRows의 가장 마지막에 들어온 행 중 처음 들어온 원소를 빼내어 1열 제일 마지막에 들어온 원소 뒤에 추가
	}
	
	// 행 한 칸씩 아래로 이동
	public static void shiftRow() {
		// 가장 마지막에 들어온 행 또는 원소를 가장 처음 위치에 넣어줘야 한다. addFirst 추가 구조이므로 스택 구조로 빼내기 위해 removeFirst, 제일 앞에 추가해줘야 하므로 addLast를 써준다.
		restRows.addLast(restRows.removeFirst()); // 행
		firstCol.addLast(firstCol.removeFirst()); // 1열
		lastCol.addLast(lastCol.removeFirst()); // 마지막열
	}
	
	public static int[][] solution(int[][] rc, String[] operations) {
		int[][] answer = {};
        
		// STEP 1. 2차원 배열 rc => 2개의 열과 나머지 행 구조로 나누기
		rcSetting(rc);
        
		// STEP 2. 메인 작업
		for (String operation : operations) { // "Rotate", "ShiftRow"
        	
			switch (operation.charAt(0)) { // 'R', 'S'
				case 'R' : rotate(); break;
				case 'S' : shiftRow(); break;
			}
		}
        
		// STEP 3. 2차원 배열 answer에 값 담기
		answer = new int[r][c];
        
		for (int i = 0; i < r; i++) {
			// addFirst 추가 구조에서 큐 구조로 빼내기 위해 removeLast 사용
			answer[i][0] = firstCol.removeLast(); // 1열
			answer[i][c - 1] = lastCol.removeLast(); // 마지막열
        	
			Deque<Integer> tempRow = new ArrayDeque<Integer>(); // restRows의 각 행을 담기 위해 tempRow 생성
        	
			// addFirst 추가 구조에서 큐 구조로 빼내기 위해 removeLast 사용
			tempRow = restRows.removeLast();
        	
			for (int j = 1; j < c - 1; j++) {
				answer[i][j] = tempRow.removeLast();
			}
		}
        
		return answer;
	}

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		int[][] rc = {{1, 2, 3}, {4, 5, 6}, {7, 8, 9}};
		String[] operations = {"Rotate", "ShiftRow"}; // Rotate : 행렬 바깥쪽에 있는 원소를 시계 방향으로 회전, ShiftRow : 행을 한 칸씩 아래로 이동
		
//		    Rotate  ShiftRow
//		1 2 3    4 1 2    8 9 6
//		4 5 6    7 5 3    4 1 2
//		7 8 9    8 9 6    7 5 9
		
		System.out.println(solution(rc, operations)); // {{8, 9, 6}, {4, 1, 2}, {7, 5, 3}}
	}
}

 

Deque 자료구조에 대해 어느 정도 학습이 된 후 풀이하는 것을 추천한다.

 

프로그래머스 행렬과 연산 문제 풀이 Java

import java.util.Arrays;
import java.util.LinkedList;
import java.util.Queue;

public class Solution {
	
	// 두 큐 합 같게 만들기
	
	public static int solution(int[] queue1, int[] queue2) {
		int answer = 0;
		int length = queue1.length;
		long queue1Sum = 0; // queue1의 합계만을 사용할 것
		long totalSum = 0;
		long targetSum = 0;
		
		Queue<Integer> q1 = new LinkedList<>();
		Queue<Integer> q2 = new LinkedList<>();
        
		queue1Sum = Arrays.stream(queue1).sum(); // 6
        
		totalSum = queue1Sum + Arrays.stream(queue2).sum(); // 20

		if (totalSum % 2 == 1) return -1; // 똑같이 나눌 수 없다면 -1 리턴
        
		targetSum = totalSum / 2; // 10 // 하나의 큐만 절반 값을 맞춘다면 okay, 절반 값을 이용
        
		for (int i = 0; i < length; i++) {
			q1.offer(queue1[i]); // 1, 2, 1, 2
			q2.offer(queue2[i]); // 1, 10, 1, 2
		}
        
		int tempNum = 0;
        
		while (queue1Sum != targetSum) {
        	
			if (queue1Sum < targetSum) {
				tempNum = q2.poll();
				q1.offer(tempNum);
				queue1Sum += tempNum;
			} else {
				tempNum = q1.poll();
				q2.offer(tempNum);
				queue1Sum -= tempNum;
			}
        	
			answer++;
        	
			// queue1, queue2의 모든 원소가 자리바꿈하여 다시 원래의 위치로 오기 위한 횟수 (queue1.length + queue2.length) * 2 = 16
			// 즉 16이 된다는 것은 다시 처음의 경우와 같아졌음을 의미하고, 더이상 반복할 필요가 없음을 뜻한다.
			if (answer > length * 4 - 1) return -1;
		}
		
		return answer;
	}

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		int[] queue1 = {1, 2, 1, 2};
		int[] queue2 = {1, 10, 1, 2};
		
		System.out.println(solution(queue1, queue2)); // 7
	}
}

프로그래머스 두 큐 합 같게 만들기 문제 풀이 Java

import java.util.*;

public class Solution {
	
	//	성격 유형 검사하기
	
	static String[] typeArr = {"RT", "CF", "JM", "AN"};
	
	public static String typeCheck(HashMap<Character, Integer> hm) {
		
		StringBuilder sb = new StringBuilder();
		
		char firstChar;
		char secondChar;
		char typeChar;
		
		for (String s : typeArr) { // "RT", "CF", "JM", "AN"
			
			firstChar = s.charAt(0); // 'R', 'C', 'J', 'A'
			secondChar = s.charAt(1);// 'T', 'F', 'M', 'N'
			
			typeChar = hm.get(firstChar) >= hm.get(secondChar) ? firstChar : secondChar;
			
			sb.append(typeChar); // 'T' + 'C' + 'M' + 'A'
		}
		
		return sb.toString(); // "TCMA"
	}
	
	public static String solution(String[] survey, int[] choices) {
		String answer = "";
		int[] score = {0, 3, 2, 1, 0, -1, -2, -3}; // choices 값에 따라 점수 부여
		
		HashMap<Character, Integer> hm = new HashMap<>(); // 타입, 점수 담을 HashMap
		
		int scoreSum = 0; // 타입별 점수를 담을 변수
		
		for (String s : typeArr) { // "RT", "CF", "JM", "AN"
			hm.put(s.charAt(0), 0); // 'R' : 0, 'C' : 0, 'J' : 0 ,'A' : 0
			hm.put(s.charAt(1), 0); // 'T' : 0, 'F' : 0, 'M' : 0 ,'N' : 0
		}
		
		for (int i = 0; i < survey.length; i++) { // "AN", "CF", "MJ", "RT", "NA"
			// 'A' 스코어 // 'C' 스코어 // 'M' 스코어 // 'R' 스코어 // 'N' 스코어 업데이트
			scoreSum = hm.get(survey[i].charAt(0)) + score[choices[i]];
			hm.put(survey[i].charAt(0), scoreSum);
		}
		
		// 'R' : -3, 'C' : 1, 'J' : 0 ,'A' : -1
		// 'T' :  0, 'F' : 0, 'M' : 2 ,'N' : -1
		answer = typeCheck(hm);
		
		return answer;
	}

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		String[] survey = {"AN", "CF", "MJ", "RT", "NA"}; // survey 원소의 첫 글자를 기준으로 점수를 부여할 것이므로 score = {0, 3, 2, 1, 0, -1, -2, -3}으로 세팅
		int[] choices = {5, 3, 2, 7, 5}; // A : += score[5] // C : += score[3] // M : += score[2] // R : += score[7] // N : += score[5]
		
		System.out.println(solution(survey, choices));
	}
}

프로그래머스 성격 유형 검사하기 문제 풀이 Java

두 번째 시도(시간 초과)

public class Solution {
	
	// 도둑질 // 두 번째 시도(시간 초과)
	
	public static int getMaxMoneyExceptTargetIndex(int[] money, int targetIndex) {
		int[] dp = new int[money.length - 1]; // 제일 먼저 1을 뺐을 경우 2,3,1,4,2,5에서 개미전사 문제
		int num1 = (targetIndex + 1) % (money.length); // 타겟 인덱스의 바로 다음 인덱스
		int num2 = (targetIndex + 2) % (money.length); // 타겟 인덱스의 다음 다음 인덱스
		int num3 = 0;
		
		dp[0] = money[num1];
		dp[1] = money[num2];
		
		for (int i = 2; i < money.length - 1; i++) {
			num3 = (targetIndex + i + 1) % (money.length);
			dp[i] = Math.max(dp[i - 2] + money[num3], dp[i - 1]);
		}
		
		return dp[money.length - 2];
	}
	
	public static int solution(int[] money) {
		int answer = 0;
		int maxMoney = 0;
        
		for (int i = 0; i < money.length; i++) {
			maxMoney = Math.max(maxMoney, getMaxMoneyExceptTargetIndex(money, i)); // i번째 인덱스를 제외했을 때의 최대 값
		}
        
		answer = maxMoney;
        
		return answer;
	}

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		int[] money = {1, 2, 3, 1, 4, 2, 5}; // 1 빼고 2,3,1,4,2,5 개미전사 문제 // 2 빼고 3,1,4,2,5,1 개미전사 문제 // 3 빼고 1,4,2,5,1,2 개미전사 문제 // 총 7개의 값 중 max값을 return
		
		System.out.println(solution(money));
	}
}

 

첫 번째 시도(★ 부분으로 인해 예외 발생)

세 번째 시도 성공

public class Solution {
	
	// 도둑질
	// 첫 번째 시도(★ 부분으로 인해 예외 발생)
	// 세 번째 시도 성공
	
	public static int solution(int[] money) {
		int answer = 0;
		int[] dpExceptLast = new int[money.length - 1]; // 1, 2, 3, 1, 4, 2 담자
		int[] dpExceptFirst = new int[money.length - 1]; // 2, 3, 1, 4, 2, 5 담자
        
		dpExceptLast[0] = money[0]; // 1
//		dpExceptLast[1] = money[1]; // 2 // ★ 첫 번째 풀이에서 예외가 발생했던 이유 !
		dpExceptLast[1] = Math.max(money[0], money[1]); // 2 // 이게 맞지
		
		dpExceptFirst[0] = money[1]; // 2
//		dpExceptFirst[1] = money[2]; // 3 // ★ 첫 번째 풀이에서 예외가 발생했던 이유 !
		dpExceptFirst[1] = Math.max(money[1], money[2]); // 3 // 이게 맞지
        
		for (int i = 2; i < money.length; i++) {
			if (i < money.length - 1) {
				dpExceptLast[i] = Math.max(dpExceptLast[i - 2] + money[i], dpExceptLast[i - 1]);
			}
        	
			if (i > 2) {
				dpExceptFirst[i - 1] = Math.max(dpExceptFirst[i - 3] + money[i], dpExceptFirst[i - 2]);
			}
		}
        
		answer = Math.max(dpExceptLast[money.length - 2], dpExceptFirst[money.length - 2]);
        
		return answer;
	}

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		int[] money = {1, 2, 3, 1, 4, 2, 5};
		
		System.out.println(solution(money));
	}
}

프로그래머스 도둑질 문제 풀이 Java

 

public class Solution {
	
	// 파괴되지 않은 건물
	
	public static int solution(int[][] board, int[][] skill) {
		int answer = 0;
		int[] arr = new int[skill[0].length];
		int startRowNum = 0;
		int startColNum = 0;
		int endRowNum = 0;
		int endColNum = 0;
		int affectPoint = 0;
        
		for (int i = 0; i < skill.length; i++) {
			arr = skill[i];
        	
			startRowNum = arr[1];
			startColNum = arr[2];
			endRowNum = arr[3];
			endColNum = arr[4];
        	
			affectPoint = (arr[0] == 1 ? -arr[5] : arr[5]);
        	
			for (int j = startRowNum; j <= endRowNum; j++) {
        		
				for (int z = startColNum; z <= endColNum; z++) {
					board[j][z] += affectPoint;
				}
			}
		}
        
		for (int j = 0; j < board.length; j++) {
    		
			for (int z = 0; z < board[j].length; z++) {
//				System.out.print(board[j][z] + " ");
				if (board[j][z] > 0) answer++;
			}
//			System.out.println();
		}
		
	return answer;
	}

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		int[][] board = {{5,5,5,5,5},{5,5,5,5,5},{5,5,5,5,5},{5,5,5,5,5}}; // 4개의 행 5개의 열
		int[][] skill = {{1,0,0,3,4,4},{1,2,0,2,3,2},{2,1,0,3,1,2},{1,0,1,3,3,1}}; // 1은 공격, 2는 회복 // {1,0,0,3,4,4}는 공격이며 0행0열 ~ 3행4열까지 4의 피해를 준다는 의미
		
		System.out.println(solution(board, skill)); // 10
	}
}

시간 초과 발생

 

<누적합 이용한 문제 풀이>

public class Solution {
	
	// 파괴되지 않은 건물
	
	public static int solution(int[][] board, int[][] skill) {
		int answer = 0;
		int N = board.length;
		int M = board[0].length;
		int[][] sumArr = new int[N+1][M+1];
		int[] infoArr = new int[skill[0].length];
		int startRowNum = 0;
		int startColNum = 0;
		int endRowNum = 0;
		int endColNum = 0;
		int affectPoint = 0;
        
		for (int i = 0; i < skill.length; i++) {
			infoArr = skill[i];
        	
			startRowNum = infoArr[1];
			startColNum = infoArr[2];
			endRowNum = infoArr[3];
			endColNum = infoArr[4];
        	
			affectPoint = (infoArr[0] == 1 ? -infoArr[5] : infoArr[5]);
        	
			sumArr[startRowNum][startColNum] += affectPoint; // 좌상 +
			sumArr[startRowNum][endColNum + 1] += -affectPoint; // 좌하 -
			sumArr[endRowNum + 1][startColNum] += -affectPoint; // 우상 -
			sumArr[endRowNum + 1][endColNum + 1] += affectPoint; // 우하 +
		}
        
        
		// 상하의 합
		for (int i = 1; i < N; i++) {
        	
			for (int j = 0; j < M; j++) {
				sumArr[i][j] += sumArr[i - 1][j];
			}
		}
        
		// 좌우의 합
		for (int j = 1; j < M; j++) {
        	
			for (int i = 0; i < N; i++) {
				sumArr[i][j] += sumArr[i][j - 1];
			}
		}
        
		for (int i = 0; i < N; i++) {
        	
			for (int j = 0; j < M; j++) {
        		
				if (board[i][j] + sumArr[i][j] > 0) {
					answer++;
				}
			}
		}
        
		return answer;
	}

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		int[][] board = {{5,5,5,5,5},{5,5,5,5,5},{5,5,5,5,5},{5,5,5,5,5}}; // 4개의 행 5개의 열
		int[][] skill = {{1,0,0,3,4,4},{1,2,0,2,3,2},{2,1,0,3,1,2},{1,0,1,3,3,1}}; // 1은 공격, 2는 회복 // {1,0,0,3,4,4}는 공격이며 0행0열 ~ 3행4열까지 4의 피해를 준다는 의미
		
		System.out.println(solution(board, skill)); // 10
	}
}

 

1 ~ 11 그림을 보면서 이해해 보자

중간에 번호가 붙지 않은 예시는 이해를 돕기 위한 설명이니 신경쓰지 않아도 된다.

 

 

공격 & 4이므로 첫 번째 값은 -4 하단과 우측 값은 4 우측 하단 값은 -4로 설정한다.

 

상하 누적 합의 범위는 N행(여기서는 4행)까지이므로 파란색 부분은 대상에서 제외

 

좌우 누적 합의 범위는 M열(여기서는 5열)까지이므로 파란색 부분은 대상에서 제외

 

 

 

 

 

 

 

 

 

 

 

프로그래머스 파괴되지 않은 건물 문제 풀이 Java

+ Recent posts