패스트캠퍼스 핵심유형 20개로 한 번에 끝내는 알고리즘 코딩테스트 with Java 강의를 정리한 내용


문자열

  • 문자로 구성된 자료형
  • String 클래스를 지원함
  • String은 불변이라 인스턴스 생성되면 수정 못함
    • 부분적으로 변경할 수는 없고 새로 만들어야함
    • charAt() : String 인덱스에 해당하는 char 출력
char[] arr = {'A', 'B', 'C'};
arr[2] = 'D';
System.out.println(arr);
// ABD
 
String str = "ABC";
str[2] = 'D';
System.out.println(str);
// 컴파일에러
 
System.out.println(str.charAt(2));
// C

String 내용 바꾸기

String 값의 변경은 불가능하지만, 새 String을 만들어서 변경할 수 있음

  1. 덮어쓰기
String str = "ABCD";
str = "ABCDE";
System.out.println(str);
// ABCDE

  1. 한글자씩 떼어난 char 배열 생성해서 수정
    • toCharArray() : String을 char 배열로 변경
String str = "ABCD";  
char[] arr = str.toCharArray();  
arr[3] = 'E';  
str = new String(arr);  
System.out.println(str);
// ABCE

  1. substring() : String 에서 부분만 뽑아내기
String str = "ABCD";  
str = str.substring(0,2) + 'E' + str.substring(3,4);  
System.out.println(str);
// ABED

String 내용 비교


String str1 = "java";
String str2 = "java";
String str3 = new String("java");
String str4 = new String("java");
 
System.out.println(str1 == str2);  
System.out.println(str1 == str3);  
System.out.println(str3 == str4);
 
// true
// false
// false
  • 리터럴로 생성한건 String Pool(=String Costant Pool)에 한 번만 생성되고 기존 값 참조
  • 인스턴스 생성한건 Heap 영역에 매번 새로 생성됨
  • 따라서 ==는 참조하는 대상이 같은지를 비교하는 것이다.
  • st3.equals(str4) 처럼 equals() 를 이용해야 String의 내용이 같은지를 물어보는 것

String 메서드


Method NameReturn valueDescription
charAt(int index)charindex에 위치한 문자
length()int문자열 길이
equals(Object anObject)boolean문자열 값의 비교
compareTo(String anotherString)int두 문자열을 사전순으로 비교한 결과
toCharArray()char[]문자열을 변환한 char 배열
toLowerCase()String모든 문자를 소문자로 변경한 새 문자열
toUpperCase()String모든 문자를 대문자로 변경한 새 문자열
contains(CharSequence s)boolean문자열을 포함하는지 여부
replace(CharSequence target,
CharSequence replacement)
Stringtarget을 모두 replacement로 바꾼 새 문자열
split(String regex)String[]정규표현식에 맞게 문자열을 여러 문자열로 분할
substring(int beginIndex, int endIndex)String[beginIndex, endIndex]를 갖는 새 문자열 반환
indexOf(int ch, int fromIndex)intfromIndex부터 ch 문자가 나타나는 가장 첫 인덱스

2744번 문제


import java.io.*;
  
public class Main {  
    public static void main(String[] args) throws IOException {  
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));  
        char[] arr = br.readLine().toCharArray();  
        for (int i = 0; i < arr.length; i++) {  
            if ('A' <= arr[i] && arr[i] <= 'Z') {  
                arr[i] = (char)('a' + arr[i] - 'A');  
            } else {  
                arr[i] = (char)('A' + arr[i] - 'a');  
            }  
            System.out.print(arr[i]);  
        }  
    }  
}
  • 이렇게 아스키코드 차이인 32를 굳이 안외워도 구할 수 있다.
    • 대문자 65 ~ 90
    • 소문자 97 ~ 122
  • 소문자로 바꾸는 과정이니까 베이스 ‘a’ 에다가 (어떤 대문자 - 대문자 기준인 ‘A’) 를 더하면 되겠네

1919번 문제


  1. 단순구현
import java.io.*;  
  
public class Main {  
    public static void main(String[] args) throws IOException {  
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));  
        String a = br.readLine();  
        String b = br.readLine();  
  
        int[] countA = new int[26];  
        int[] countB = new int[26];  
  
        for (int i = 0; i < a.length(); i++) {  
            countA[(a.charAt(i) - 'a')]++;  
        }  
  
        for (int i = 0; i < b.length(); i++) {  
            countB[(b.charAt(i) - 'a')]++;  
        }  
  
        int result = 0;  
  
        for (int i = 0; i < 26; i++) {  
            if (countA[i] > countB[i]) {  
                result += countA[i] - countB[i];  
            }  
            else if (countB[i] > countA[i]) {  
                result += countB[i] - countA[i];  
            }  
        }  
        System.out.println(result);  
    }  
}
  1. 중복을 메서드로 빼보기
import java.io.*;  
  
public class Main {  
    public static int[] getAlphabetCount(String str) {  
        int[] count = new int[26];  
        for (int i = 0; i < str.length(); i++) {  
            count[(str.charAt(i) - 'a')]++;  
        }  
        return count;  
    }  
    public static void main(String[] args) throws IOException {  
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));  
        String a = br.readLine();  
        String b = br.readLine();  
  
        int[] countA = getAlphabetCount(a);  
        int[] countB = getAlphabetCount(b);  
  
        int result = 0;  
  
        for (int i = 0; i < 26; i++) {  
            result += Math.abs(countA[i] - countB[i]);  
        }  
        System.out.println(result);  
    }  
}

1157번 문제


import java.io.*;  
  
public class Main {  
    public static int[] AlphabetCount(String str) {  
        int[] count = new int[26];  
        for (int i = 0; i < str.length(); i++) {  
            count[(str.charAt(i) - 'A')]++;  
        }  
  
        return count;  
    }  
  
    public static void main(String[] args) throws IOException {  
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));  
        String str = br.readLine().toUpperCase();  
        int[] count = AlphabetCount(str);  
  
        int maxCount = -1;  
        char maxAlphabet = '?';  
        for (int i = 0; i < 26; i++) {  
            if (count[i] > maxCount) {  
                maxCount = count[i];  
                maxAlphabet = (char)('A' + i);  
            } else if (count[i] == maxCount) {  
                maxAlphabet = '?';  
            }  
        }  
        System.out.println(maxAlphabet);  
    }  
}

1543번 문제

pseudo-coe

1번 : 문서의 첫 글자부터 순회

for (int i = 0; i < docs.length(); i++) {
 
}

2번 : 문서의 지금 글자부터 주어진 단어와 한 글자씩 비교

for (int i = 0; i < docs.length(); i++) {
	for (int j = 0; j < word.length(); j++) {
		if (docs.charAt(i+j) != word.charAt(j)) {
			// 문서에서 i번째 인덱스부터 시작하는 단어는
			// 주어진 단어와 일치하지 않는다.
		}
	}
}


3번 : 단어와 완전히 일치하면 개수를 올리고, 해당 단어가 등장한 이후부터 2번 과정 반복

4번 : 단어와 매치되지 않았다면 다음 글자에서 2번 과정 반복

for (int i = 0; i < docs.length(); i++) {
	boolean isMatch = true;
	for (int j = 0; j < word.length(); j++) {
		if (docs.charAt(i+j) != word.charAt(j)) {
			isMatch = false;
			break;
		}
	}
}
  • 그런데, 여기서 i = docs.length() - 1이고 j = 1이면, i + j = docs.length()가 되버리니까 index 범위 넘어서 런타임에러 발생
  • 인덱스를 다룰 때는 항상 범위체크하자.
for (int i = 0; i < docs.length(); i++) {
	boolean isMatch = true;
	for (int j = 0; j < word.length(); j++) {
		if ( i + j >= docs.length() || docs.charAt(i+j) != word.charAt(j)) {
			isMatch = false;
			break;
		}
	}
 
	if (isMatch) {
		count++;
		i += word.length() - 1;
	}
}
  • 중복되지 않는 단어를 찾아야함. 지금 찾은거랑 중복되면 안됨.
  • word.length() ? word.length() - 1 뭐 더해?
    • i 루프가 1을 더해주니까 그걸 감안해서 -1을 해줘야함
    • (( length() -1 ) + 1)

indexOf(word, startIndex) 메서드 사용하면 더 편함!

  • docs 문자열의 startIndex부터 처음으로 등장하는 word 문자열을 찾음
  • 찾았다면 일치하는 시작 인덱스 반환, 찾지 못하면 -1 반환
import java.io.*;  
  
public class Main {  
    public static void main(String[] args) throws IOException {  
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));  
        String docs = br.readLine();  
        String word = br.readLine();  
  
        int count = 0;  
        int startIndex = 0;  
        while (true) {  
            int findIndex = docs.indexOf(word, startIndex);  
            if (findIndex < 0)  
                break;  
            count++;  
            startIndex = findIndex + word.length();  
        }  
        System.out.println(count);  
    }  
}
  • for문에서 인덱스에 더해주던것과는 다르게 여기서는 더해주는 값이 없으니까 그냥 바로 word.length()를 해줬음

replace() 이용

import java.io.*;  
  
public class Main {  
    public static void main(String[] args) throws IOException {  
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));  
        String docs = br.readLine();  
        String word = br.readLine();  
  
        String replaced = docs.replace(word, "");  
        int length = (docs.length() - replaced.length()) / word.length();  
        System.out.println(length);  
    }  
}
  • docs가 “aaaaaaaa”, word가 “aaa”라고 하자.
  • docs.length는 8, word.length는 3이다.
  • 중복되는걸 없애고 나면 “aa”만 남게 될 것이고 length는 2이다.
  • 그럼 결과적으로 몇 번 중복됐는지를 확인하려면 word의 길이만큼 나누면 되겠네
  • docs.length() - replaced.length()를 하고 나누기 word.length()

13223번 문제

HH:MM:SS 포맷에서 쪼개는 방법 3가지

  1. 각 단위 인덱스에서 10의 자리와 1의 자리 구해서 계산
    • 아스키코드 빼주고 자릿수 곱하기
String time = "09:02:43"
int hour = (time.charAt(0) - '0') * 10 + (time.charAt(1) - '0');
int min = (time.charAt(3) - '0') * 10 + (time.charAt(4) - '0');
int sec = (time.charAt(6) - '0') * 10 + (time.charAt(7) - '0');

  1. substring(시작인덱스, 끝인덱스) 시작 인덱스부터 끝 인덱스 전까지
String time = "09:02:43"
int hour = Integer.parseInt(time.substring(0, 2));
int min = Integer.parseInt(time.substring(3, 5));
int sec = Integer.parseInt(time.substring(6, 8));

  1. split("")
String[] time = "09:02:43".split(":");
int hour = Integer.parseInt(time[0]);
int min = Integer.parseInt(time[1]);
int sec = Integer.parseInt(time[2]);

시간 계산법 2가지

  1. 가장 작은 단위부터 음수가 나오면 더 큰 단위에서 내림하여 가져오기
if (sec < 0) {
	sec += 60;
	min--;
}
 
if (min < 0) {
	min += 60;
	hour--;
}
 
if (hour < 0) {
	hour += 24;
}

  1. 계층적으로 표현되는 각 단위 계산 시, 가장 작은 단위로 통일
int now_calc = now_hour * 3600 + now_min * 60 + now_sec;
int insert_calc = insert_hour * 3600 + insert_min * 60 + insert_sec;
 
int result_calc = insert_calc - now_calc;  
 
if (result_calc < 0)  
    result_calc += 24 * 3600;  
  
int result_hour = result_calc / 3600;  
int result_min = (result_calc % 3600) / 60;  
int result_sec = result_calc % 60;
  • 1시간 = 60분 = 3600초
  • 예를 들어, 10000초라고 해보자.
  • 10000초 = 3600 * (2시간) + 2800초
    • 몫이 2, 나머지 2800
  • 2800초 = 60 * (46분) + 40초
  • 10000초 = 2시간 46분 40초

문자열 포맷 코드로 출력


코드설명
%s문자열(String)
%c문자 1개(character)
%d정수 (Integer)
%f부동소수 (floating-point)
%o8진수
%x16진수
%%Literal % (문자 % 자체)

System.out.printf("%02d:%02d:%02d", h, m, s);
  • C에서처럼 똑같이 printf 쓰기
  • %02d는 정수를 출력할건데, 최소 2자리수로 맞춰주고 자리가 남으면 앞에 0으로 채우라는 의미
  • %3.f는 소수를 출력할건데, 소수점 아래 3자리까지 출력

작은 단위로 통일한 코드 버전

import java.io.*;  
  
public class Main {  
    public static void main(String[] args) throws IOException {  
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));  
        String[] now_time = br.readLine().split(":");  
        String[] insert_time = br.readLine().split(":");  
  
        int now_hour = Integer.parseInt(now_time[0]);  
        int now_min = Integer.parseInt(now_time[1]);  
        int now_sec = Integer.parseInt(now_time[2]);  
        int now_calc = now_hour * 3600 + now_min * 60 + now_sec;  
  
        int insert_hour = Integer.parseInt(insert_time[0]);  
        int insert_min = Integer.parseInt(insert_time[1]);  
        int insert_sec = Integer.parseInt(insert_time[2]);  
        int insert_calc = insert_hour * 3600 + insert_min * 60 + insert_sec;  
  
        int result_calc = insert_calc - now_calc;  
        if (result_calc <= 0)  
            result_calc += 24 * 3600;  
  
        int result_hour = result_calc / 3600;  
        int result_min = (result_calc % 3600) / 60;  
        int result_sec = result_calc % 60;  
  
        System.out.printf("%02d:%02d:%02d", result_hour, result_min, result_sec);  
    }  
}

생각하고 푼 버전

import java.io.*;  
  
public class Main {  
    public static void main(String[] args) throws IOException {  
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));  
        String[] now = br.readLine().split(":");  
        String[] insert = br.readLine().split(":");  
  
        int h = Integer.parseInt(insert[0]) - Integer.parseInt(now[0]);  
        int m = Integer.parseInt(insert[1]) - Integer.parseInt(now[1]);  
        int s = Integer.parseInt(insert[2]) - Integer.parseInt(now[2]);  
  
        if (s < 0) {  
            s += 60;  
            m--;  
        }  
  
        if (m < 0) {  
            m += 60;  
            h--;  
        }  
  
        if (h < 0) {  
            h += 24;  
        }  
  
        if (h == 0 && m == 0 && s == 0) {  
            h = 24;  
        }  
  
        System.out.printf("%02d:%02d:%02d", h, m, s);  
    }  
}