Skip to main content

250822


  • 다단계칫솔판매 ok - 시간날 때 객체지향으로 변환, 포스팅
  • 행렬의덧셈 ok
  • 최댓값과 최솟값 ok
  • 직사각형 별찍기 ok 포스팅 - 이중for문 입력순서, repeat
  • 최솟값 만들기 ok - 포스팅 - 그리디
  • JadenCase 문자열 만들기 ok - 포스팅 split 메서드의 한계
  • 이진 변환 반복하기 푸는 중
  • 크기가 작은 부분 문자열 ok - 포스팅 compareTo메서드, 길이 주의사항


노트북에 크롬, 인텔리제이, 이클립스, VSCode, WSL(리눅스) 환경 세팅 + 스티커 붙이기

빛가람 도서관 2권 반납 + 1권 연장 ok


크기가 작은 부분 문자열

첫번째 시도

class Solution {
    public int solution(String t, String p) {
        int len = p.length();
        int count = 0;
        
        
        for(int i = 0; i < t.length() - len; i++) {
            long subNum = Long.parseLong(t.substring(i, i + len));
            long pNum = Long.parseLong(p);
            if (subNum < pNum) {
                count++;
            };
        }
        
        return count;
    }
}

틀린 이유

1. 루프 범위 문제

for(int i = 0; i < t.length() - len; i++)
  • 이렇게 하면 마지막 부분 문자열을 검사하지 못함.
  • <= 로 바꿔야 마지막 부분 문자열까지 검사 가능

2. 비교 연산 문제

if (subNum < pNum)
  • 문제에서는 부분 문자열 <= p 인 경우도 세야 한다.
  • 그런데 < 만 쓰면 같은 값(subNum == pNum) 은 카운트되지 않는다.
  • <= 로 바꿔야 마지막 부분 문자열까지 카운팅 가능
if (subNum <= pNum)

3. 반복문 안에서 pNum 계속 변환

long pNum = Long.parseLong(p);
  • 매 반복마다 변환하고 있음 → 불필요하게 반복 연산
  • 반복문 밖에서 한 번만 변환하도록 위치를 for문 위쪽으로 변경했다.

두번째시도 (정답코드)

class Solution {
    public int solution(String t, String p) {
        int len = p.length();
        int count = 0;
        long pNum = Long.parseLong(p);
        
        for(int i = 0; i <= t.length() - len; i++) {
            long subNum = Long.parseLong(t.substring(i, i + len));

            if (subNum <= pNum) {
                count++;
            };
        }
        
        return count;
    }
}

개선한 코드

class Solution {
    public int solution(String t, String p) {
        int len = p.length();
        int count = 0;
        
        for (int i = 0; i <= t.length() - len; i++) {
            String sub = t.substring(i, i + len); // 부분 문자열
            if (sub.compareTo(p) <= 0) {         // 문자열 끼리 비교
                count++;
            }
        }
        
        return count;
    }
}

부분 문자열 길이를 p와 같게 맞춘 뒤 compareTo 사용하면 숫자 문자열 비교 가능

1. compareTo 메서드

자바에서 String.compareTo(String other) 는 문자열 사전식 비교를 해주는 메서드이다.

  • 반환값:
    • 0 → 두 문자열이 같음
    • 양수 → 첫 문자열이 사전상 더 뒤에 있음
    • 음수 → 첫 문자열이 사전상 더 앞에 있음

즉,

"abc".compareTo("abd")  // 결과: -1 ("abc"가 앞)
"abc".compareTo("abc")  // 결과: 0
"abd".compareTo("abc")  // 결과: 1 ("abd"가 뒤)

2. 숫자로만 이루어진 문자열에도 적용가능하다. 이 때 길이가 중요하다.

  • 길이가 같으면 사전식 비교 = 숫자 비교 와 같음
"123".compareTo("234")  // 음수 → "123" < "234"
"456".compareTo("456")  // 0 → 같음
"789".compareTo("123")  // 양수 → "789" > "123"
  • 중요: 길이가 다르면 사전식 비교라서 작은 자리수부터 비교됨
  • 숫자 비교와 같지 않음 → 항상 길이가 같아야 안전하다
예: "99".compareTo("100") → 결과: 양수 ('9' > '1' 비교)


JadenCase 문자열 만들기

첫번째시도

class Solution {
    public String solution(String s) {
        StringBuilder sb = new StringBuilder();
        
        String[] str = s.split(" ");
        for (int i = 0; i < str.length; i++) {
            char first = str[i].charAt(0);
            // 첫 번째 문자가 숫자인지 확인
            if (Character.isDigit(first)) {
                sb.append(first); // 숫자면 그대로 StringBuilder에 추가
            } else {
                sb.append(Character.toUpperCase(first)); // 숫자가 아니라면 대문자로 전환
            }
            
            if (str[i].length() > 1) {
                sb.append(str[i].substring(1).toLowerCase()); // 1번 인덱스부터 잘라서 소문자로 전환 후 추가
                sb.append(" "); // 공백 추가
            }
        }
        
        return sb.toString().trim(); // 마지막 공백 제거
    }
}
image.png

틀린 이유 & 수정 사항

  • "공백문자가 연속해서 나올 수 있습니다" 처리 ​추가해서 수정

두번째 시도

class Solution {
    public String solution(String s) {
        StringBuilder sb = new StringBuilder();
        
        String[] str = s.split(" ", -1);
        for (int i = 0; i < str.length; i++) {
            if(str[i].length() == 0) { // 여기서 처리  str[i].equals(" ") 도 됨
                sb.append(" ");
                continue;
            }
            char first = str[i].charAt(0);
            if (Character.isDigit(first)) {
                sb.append(first);
            } else {
                sb.append(Character.toUpperCase(first));
            }
            
            if (str[i].length() > 1) {
                sb.append(str[i].substring(1).toLowerCase());
                sb.append(" ");
            }
        }
        
        return sb.toString().trim();
    }
}

틀린 이유 & 수정 사항

  • trim() 제거 → 원본 문자열 끝 공백 보존
  • if (i < str.length - 1) sb.append(" ");
    → 마지막 단어 뒤에는 불필요한 공백 안 넣고, 중간에는 넣도록 if문 두 개로 나눔

세 번째 시도

class Solution {
    public String solution(String s) {
        StringBuilder sb = new StringBuilder();
        
        String[] str = s.split(" ", -1);
        for (int i = 0; i < str.length; i++) {
            if(str[i].length() == 0) {
                sb.append(" ");
                continue;
            }
            char first = str[i].charAt(0);
            if (Character.isDigit(first)) {
                sb.append(first);
            } else {
                sb.append(Character.toUpperCase(first));
            }
            
            if (str[i].length() > 1) {
                sb.append(str[i].substring(1).toLowerCase());
            }
            
            if (i < str.length - 1) {
                sb.append(" ");
            }
        }
        
        return sb.toString();
    }
}

image.png

계속 8번케이스만 오류남

틀린 이유

  • split()메서드의 한계
  • 문자열 끝에 공백이 여러 개 있으면 split(" ", -1) 이든 split(" ", 0) 이든 결과에 빈 문자열 여러 개가 붙는다.
  • 즉, 단어 사이 연속 공백 처리는 가능하다. 중간 공백은 배열 안 빈 문자열로 잡아서 " " 처리 가능하기 때문이다.
  • 하지만 끝 공백이나 split로 쪼갤 수 없는 일부 공백은 반영되지 않는다. 즉, split 기반 코드로는 끝 공백 처리 불가
  • 프로그래머스 JadenCase 문제에서는 입력 그대로 공백 유지가 필수이므로, split 방식으로는 항상 일부 반례에서 틀림

반례

// " for the what 1what " 같은 입력을 split하면
["", "", "for", "the", "what", "1what"]
입력값 〉   "  for the what 1what  "
기댓값 〉   "  For The What 1what  "
내코드 〉   " For The What 1what" (끝 공백 없음)

네 번째 시도 (정답코드)

class Solution {
    public String solution(String s) {
        StringBuilder sb = new StringBuilder();
        
        String[] str = s.split(" ", 0); // split 사용, 마지막 빈 문자열 제외
        for (int i = 0; i < str.length; i++) {
            if (str[i].equals("")) {
                sb.append(" ");
                continue;
            }
            
            char first = str[i].charAt(0);
            if (Character.isDigit(first)) {
                sb.append(first);
            } else {
                sb.append(Character.toUpperCase(first));
            }
            
            if (str[i].length() > 1) {
                sb.append(str[i].substring(1).toLowerCase());
            }
            
            if (i < str.length - 1) {
                sb.append(" ");
            }
        }
        
        // 원본 문자열 끝 공백 유지
        int originalLength = s.length();
        while (sb.length() < originalLength) {
            sb.append(" ");
        }
        
        return sb.toString();
    }
}
  • split으로 단어 처리 → 단어 첫 글자 대문자, 나머지 소문자, 숫자 처리
  • 배열 안 빈 문자열 → " "로 처리 → 연속 공백 유지
  • 반복 끝난 후 sb 길이 < 원본 문자열 길이이면, 부족한 공백 추가 → 끝 공백 유지

개선한 코드 - split() 사용하지 않고, 문자열을 처음부터 끝까지 순회하면서 처리하는 방법이 가장 안전함.

class Solution {
    public String solution(String s) {
        StringBuilder sb = new StringBuilder();
        boolean isFirst = true; // 단어 첫 글자인지 여부

        for (char c : s.toCharArray()) {
            if (c == ' ') {
                sb.append(c);
                isFirst = true; // 다음 글자는 단어 첫 글자
            } else {
                if (isFirst) {
                    sb.append(Character.isLetter(c) ? Character.toUpperCase(c) : c);
                    isFirst = false;
                } else {
                    sb.append(Character.toLowerCase(c));
                }
            }
        }

        return sb.toString();
    }
}
  • 연속 공백 → 그대로 유지
  • 숫자로 시작하는 단어 → 그대로 처리
  • 끝 공백 → 그대로 유지
  • split 때문에 발생하는 마지막 공백 누락 문제 완전히 해결


최솟값 만들기

  • A를 오름차순 B를 내림차순으로 정렬해서
  • 같은 인덱스끼리 곱하면 항상 최소 합을 보장한다
  • 와이? 작은 수는 큰 수와 곱하는게 항상 더 유리하다
import java.util.*;

class Solution
{
    public int solution(int []A, int []B) {
        int answer = 0;
        Arrays.sort(A);
        Arrays.sort(B);
        
        for (int i = 0; i < A.length; i++) {
            answer += A[i] * B[B.length - 1 - i];
        }

        return answer;
    }
}


최댓값과 최솟값

image.png

  • Arrays.sort()로 음수값 포함된 숫자 정렬하면 안됨
  • Arrays.sort(String[])은 사전순(lexicographical order) 정렬
  • 즉, 첫번째 문자부터 유니코드(ASCII)값 기준으로 비교한다.
  • 첫 글자가 '-' → 아스키코드 45
  • 두 번째 글자는 '1'은 49, '4'는 52라서
  • 비교걸과 '1'(49) < '4'(52)라서 -1이 -4보다 앞에 옴
import java.util.Arrays;

class Solution {
    public String solution(String s) {
        String[] str = s.split(" ");
        
        int[] nums = new int[str.length];
        for (int i = 0; i < str.length; i++) {
            nums[i] = Integer.parseInt(str[i]);
        }
        
        Arrays.sort(nums);
        
        return nums[0] + " " + nums[nums.length - 1];
    }
}
  1. split(" ") → 공백으로 나누기
  2. 문자열을 숫자로 변환한 후 정렬
  3. 숫자 배열 정렬
  4. 최소값 최대값 반환


직사각형 별찍기

import java.util.Scanner;

class Solution {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        int n = sc.nextInt(); // 가로
        int m = sc.nextInt(); // 세로
        
        for (int i = 0; i < m; i++) {
            for (int j = 0; j < n; j++) {
                System.out.print("*");
            }
            System.out.println();
        }
    }
}

repeat

import java.util.Scanner;

class Solution {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        int n = sc.nextInt(); // 가로
        int m = sc.nextInt(); // 세로
        String line = "*".repeat(n);
        for (int i = 0; i < m; i++) {
            System.out.println(line);
        }
        sc.close();
    }
}


행렬의 덧셈

import java.util.Arrays;

class Solution {
    public int[][] solution(int[][] arr1, int[][] arr2) {
        int[][] answer = new int[arr1.length][arr1[0].length];
        for (int i = 0; i < arr1.length; i++) {
            for (int j = 0; j < arr1[0].length; j++) {
                answer[i][j] = arr1[i][j] + arr2[i][j];
            }
        }
        return answer;
    }
}