잘라서 배열로 저장하기

📑 문1) 문자열 my_str과 n이 매개변수로 주어질 때, my_str을 길이 n씩 잘라서 저장한 배열을 return하도록 solution 함수를 완성해주세요.


입출력 예

|my_str|n|result|
|:----:|:-:|:--:|씩 잘라서 저장한 배열을 return하도록 solution 함수를 완성해주세요.
|"abc1Addfggg4556b"|6|["abc1Ad", "dfggg4", "556b"]|
|"abcdef123"|3| ["abc", "def", "123"]|


입출력 예 설명

  • "abc1Addfggg4556b" 를 길이 6씩 잘라 배열에 저장한 ["abc1Ad", "dfggg4", "556b"]를 return해야 합니다
  • "abcdef123" 를 길이 3씩 잘라 배열에 저장한 ["abc", "def", "123"]를 return해야 합니다.

유의사항

  • 입출력 예 #1의 경우 "abc1Addfggg4556b"를 길이 6씩 자르면 "abc1Ad", "dfggg4" 두개와 마지막 "556b"가 남습니다. 이런 경우 남은 문자열을 그대로 배열에 저장합니다.

나의 풀이

package 프로그래머스;

public class CutArray {
	public static String[] solution(String my_str, int n) {
        
        String[] answer ;
        int length = my_str.length();
        
        
		if(my_str.length() % n == 0) {
			answer = new String[my_str.length()/n];
		}else {
			answer = new String[(my_str.length()/n) + 1 ];
		}
		
        for(int i = 0; i < answer.length; i++) {
        	if(length - n < 0) {
        		answer[i] = my_str.substring(n*i, my_str.length());
        		
        	}else {
        		answer[i] = my_str.substring(n*i, n*(i+1));
        		length -=n;
        	}
        }
        
        return answer;
    }
	
	public static void main(String[] args) {
		solution("abcdef123",3);
	}

}

나의 생각

my_str.length()n으로 나눈 나머지가 0인 것과, 아닌것으로 String[] 배열의 크기를 지정해주는데, 나머지가 0 이라는 것은 배열의 길이가 똑같은 크기로 딱 맞게 떨어짐을 의미한다(나누어 떨어지지 않는 경우 마지막에 추가로 한개의 배열 요소를 추가). 그리고 for문을 통해, answer 배열에 String의 substring 메서드를 사용하여 시작 index와 끝 index로 원래의 배열을 짜른는 방법을 사용하였다. if(length - n < 0) 는 배열의 크기가 다른 Index가 존재하면 이는 마지막 배열 요소에 남은 문자열 전체를 저장한다는 의미가 된다. else 문에서는 answer 배열에 my_str의 문자열을 일정한 크기로 자른뒤, length의 길이를 for문에서 n만큼 빼 결국 남은length는 일정한 크기로 자르고 남은 부분을 담는다는 의미이다.

이번 문제는 머릿속으로 생각한 부분을 그대로 코드로 구현하였다는 점에서 한 단계 앞으로 나아갔다는 기분이 들었다. 앞으로는 코드에서 불필요한 부분까지 한 걸음더 생각하여 문제해결 할 수 있도록 해야겠다.


문자열 계산하기

📑 문2) my_string은 "3 + 5"처럼 문자열로 된 수식입니다. 문자열 my_string이 매개변수로 주어질 때, 수식을 계산한 값을 return 하는 solution 함수를 완성해주세요.


제한사항

  • 연산자는 +,- 만 존재합니다.
  • 문자열의 시작과 끝에는 공백이 없습니다.
  • 0으로 시작하는 숫자는 주어지지 않습니다.
  • 잘못된 수식은 주어지지 않습니다.
  • 5 ≤ my_string의 길이 ≤ 100
  • my_string을 계산한 결과값은 1 이상 100,000 이하입니다.
    • my_string의 중간 계산 값은 -100,000 이상 100,000 이하입니다.
    • 계산에 사용하는 숫자는 1 이상 20,000 이하인 자연수입니다.
    • my_string에는 연산자가 적어도 하나 포함되어 있습니다.
  • return type 은 정수형입니다.
  • my_string의 숫자와 연산자는 공백 하나로 구분되어 있습니다.

입출력 예

my_stringresult
"3 + 4"7

입출력 예 설명

  • 3 + 4 = 7을 return 합니다.

나의 생각

첫번째 방법 (잘못생각한 풀이)

package 프로그래머스;

public class StringCal {
	public static int solution(String my_string) {
        int answer = 0;
        
        for(int i = 0; i < my_string.length(); i++) {
        	char ch = my_string.charAt(i);
        	if(Character.isDigit(ch)) {
        	answer = (int)ch-(int)'0'; // answer = 3
        	System.out.println(answer);
        	}else if(ch == '+') { // '+' = 42
        		answer += (int)ch-(int)'0';
        		System.out.println(answer);
        	}else if(ch == '-') { // '-' = 45
        		answer -= (int)ch-(int)'0';
        		System.out.println(answer);
        	}
        	
        }
        return answer;
    }
	
	public static void main(String[] args) {
		solution("3 + 4 - 6");
	}

}

Character 클래스의 메서드를 사용해서 숫자를 판별하고, +, -를 판별해서 덧셈과 뺄셈 연산을 처리하면 되지않을까 라고 생각을 하고 문제에 접근...

두번째 방법 (정답)

package 프로그래머스;

public class StringCal {
   public static int solution(String my_string) {
        int answer = 0;
        String[] str = my_string.split(" ");
        answer += Integer.parseInt(str[0]);  
       
        
        for(int i = 1; i < str.length -1 ; i++) {
        	if(str[i].equals("+")) {
        		answer += Integer.parseInt(str[i+1]);
        	}
        	if(str[i].equals("-")) {
        		answer -= Integer.parseInt(str[i+1]);
        	}
        }

        return answer;
    }
   
   public static void main(String[] args) {
      solution("3 - 4 - 6");
   }

}

나의 생각

먼저, my_string 문자열을 String[] 배열에 담는데, 공백없이 배열에 담기 위해 " "를 사용하였다. answer += Integer.parseInt(str[0]) 는 answer에 my_string문자열의 첫글자를 더하여 for문의 특정 조건 ( "+" , "-") 일때 검출된 문자를 int형으로 변환하여 더하거나 빼주기 위한 로직이다. str.length - 1의 조건 역시, 전체 배열 크기만큼 반복을 돌려도 상관 없으나, 전체 배열의 마지막 배열index에는 숫자가 반드시 들어 있기때문에, str.length-1 을 하여 연산자(+,-)까지만 반복을 돌린다는 의미이다.


구슬을 나누는 경우의 수

📑 문3) 머쓱이는 구슬을 친구들에게 나누어주려고 합니다. 구슬은 모두 다르게 생겼습니다. 머쓱이가 갖고 있는 구슬의 개수 balls와 친구들에게 나누어 줄 구슬 개수 share이 매개변수로 주어질 때, balls개의 구슬 중 share개의 구슬을 고르는 가능한 모든 경우의 수를 return 하는 solution 함수를 완성해주세요.


입출력 예

ballsshareresult
323
5310

입출력 예 설명

  • 서로 다른 구슬 3개 중 2개를 고르는 경우의 수는 3입니다.

  • 서로 다른 구슬 5개 중 3개를 고르는 경우의 수는 10입니다.

hint

n!(nm)!m!\frac{n!}{(n-m)!m!}


나의 풀이

오답( 테스트 클래스 오답)

package programmers;

public class NumberOfCases {
	public static long solution(int balls, int share) {
      
        long n = 1;
        long m = 1;
        
      
        for(int i = balls; i > balls - share; i--) {
        	n*=i;
        }
        for(int j =share; j > 0; j--) {
        	m*=j;	
        }
        
        return n/m;
    }
	
	public static void main(String[] args) {
		solution(5,2);
	}

}

BigInteger (정답)

package programmers;

import java.math.BigInteger;

public class NumberOfCases {
	public static BigInteger solution(int balls, int share) {
      
       BigInteger numerator = BigInteger.ONE;
       BigInteger denominator = BigInteger.ONE;
       
       for (int i = balls; i > balls - share; i--) {
           numerator = numerator.multiply(BigInteger.valueOf(i));
       }
       for (int i = share; i > 0; i--) {
           denominator = denominator.multiply(BigInteger.valueOf(i));
       }
       
       System.out.println(numerator.divide(denominator));
       return numerator.divide(denominator);
       
    }
	
	public static void main(String[] args) {
		solution(5,2);
	}

}



나의 풀이

문제에서 힌트까지 준거보면 문제를 막연히 풀기보단, overflow를 어떻게 해결할 것인가를 중점적으로 해결해야 하는거같다. 나는 java의 BigInteger 클래스를 활용하여 문제를 풀었지만, 문제의 의도는 점차 늘어나는 자리수의 문제를 overflow 없이 어떻게 해결 할 것인가? 를 생각해보라는 의미였던거 같다.


재귀적 풀이 (recursive)

class Solution {
    public int solution(int balls, int share) {
        int answer = 0;
        if(balls == share || share == 0) 
            answer = 1; 
        else{
            answer = solution(balls - 1, share - 1) + solution(balls - 1, share);
        } 

        return answer;
    }
}
  • 입력 : 두 정수 balls와 share
  • 출력 : balls개의 공을 share 명의 사람에게 나누어주는 방법의 수
  • 이 함수는 다음과 같은 점화식을 사용하여 문제를 해결합니다.
  1. 기저 조건(base case) : 만약 balls와 share가 같거나 share가 0이면, 리턴은 1입니다. 이것은 모든 공을 동일한 수로 나눌 수 있거나 공을 나눌 필요가 없는 경우를 의미
  2. 재귀적 접근(recursive approach) : 그렇지 않으면, 함수는 다음 두 가지 경우의 합을 반환
  • balls - 1 개의 공을 share - 1명의 사람들에게 나누어주는 방법의 수 : 이 경우는 각 사람들이 최소한 하나의 공을 가지고 있는 경우를 의미함
  • balls - 1 개의 공을 share 명의 사람들에게 나누어주는 방법의 수 : 이 경우 적어도 한 사람이 공을 받지 않는 경우를 의미함

삼각형의 완성조건 (2)

📑 문4) 선분 세 개로 삼각형을 만들기 위해서는 다음과 같은 조건을 만족해야 합니다. 가장 긴 변의 길이는 다른 두 변의 길이의 합보다 작아야 합니다. 삼각형의 두 변의 길이가 담긴 배열 sides이 매개변수로 주어집니다. 나머지 한 변이 될 수 있는 정수의 개수를 return하도록 solution 함수를 완성해주세요.


입출력 예

sidesresult
[1,2]1
[3,6]5
[11,7]13

입출력 예 설명

입출력 예 #1

  • 두 변이 1, 2 인 경우 삼각형을 완성시키려면 나머지 한 변이 2여야 합니다. 따라서 1을 return합니다.

입출력 예 #2

  • 가장 긴 변이 6인 경우
    • 될 수 있는 나머지 한 변은 4, 5, 6 로 3개입니다.
    • 나머지 한 변이 가장 긴 변인 경우 될 수 있는 한 변은 7, 8 로 2개입니다.
  • 따라서 3 + 2 = 5를 return합니다.

입출력 예 #3

  • 가장 긴 변이 11인 경우
    • 될 수 있는 나머지 한 변은 5, 6, 7, 8, 9, 10, 11 로 7개입니다.
  • 나머지 한 변이 가장 긴 변인 경우
    • 될 수 있는 한 변은 12, 13, 14, 15, 16, 17 로 6개입니다.
  • 따라서 7 + 6 = 13을 return합니다.

나의 풀이

package programmers;

public class TriangleCompletion {
	public static int solution(int[] sides) {
        
  
        int max = Math.max(sides[0], sides[1]);
        int min = Math.min(sides[0], sides[1]);
        int cnt = 0;
   
        
        for(int i = (max - min)  ; i < max; i++) {
        	cnt++;
        }
        
        for(int i = max+1; i < max+min; i++) {
        	cnt++;
        }
        return cnt;
    }
	
	public static void main(String[] args) {
		
		solution(new int[] {3,6});
	}

}

나의 생각

입출력 예 #3 의 설명을 바탕으로 로직을 구성해 보았다.

  • 가장 긴 변이 11인 경우
    • 될 수 있는 나머지 한 변은 5, 6, 7, 8, 9, 10, 11 로 7개입니다.
  • 나머지 한 변이 가장 긴 변인 경우
    • 될 수 있는 한 변은 12, 13, 14, 15, 16, 17 로 6개입니다.
  • 따라서 7 + 6 = 13을 return합니다.

매개변수로 두 변수가 주어졌을때, 두 수 중에 큰 수와 작은 수를 판별을 먼저 해야하기 때문에

Math 클래스의 max,min 메서드를 활용하여 max, min 값을 판별하였다. 그리고 가장 긴 별이 max 일 경우와 나머지 한 변의 길이가 가장 긴 경우로 나누어 for문을 돌려 마지막으로 cnt(카운트)를 리턴하였다. 문제 해결을 아주 직관적으로 풀었는데, 이를 좀 더 클린하게 표현하면 다음과 같다.

int max = Math.max(sides[0], sides[1]);
int min = Math.min(sides[0], sides[1]);

java의 내부 클래스와 메서드를 활용하는 방법도 좋은 방법이지만 때로는 원리적으로 문제를 풀 줄도 알아야 하기에 Math 클래스 대신 아래와 같은 방법도 사용할 수 있다.

int max = sides[0] > sides[1] ? sides[0] : sides[1]
int min = sides[0] > sides[1] ? sides[1] : sides[0]

삼항 연산자 를 활용하여 max 값과 , min 값을 구할 수 있다. 그리고 아래의 for문 두 개를 보면 공통점을 발견할 수 있다.

두 조건을 더해보자

int i = max - min + max +1; i < max + max + min
int i = 2max - min + 1; i < 2max + min (i에 2max - min + 1을 대입)
2max - min + 1 < 2max + min
따라서, 나머지 한 변이 될 수 있는 정수의 개수를 이항 정리를 하면 2 * min - 1 가 성립된다. 위 조건을 바탕으로 코드를 재구성하면 아래와 같다.

package programmers;

public class TriangleCompletion {
	public static int solution(int[] sides) {
        
		int max = sides[0] > sides[1] ? sides[0] : sides[1];
		int min = sides[0] > sides[1] ? sides[1] : sides[0];
		
		
		
		return 2 * min - 1;
    }
	
	public static void main(String[] args) {
		
		solution(new int[] {11,7});
	}

}


외계어 사전

📑 문5) PROGRAMMERS-962 행성에 불시착한 우주비행사 머쓱이는 외계행성의 언어를 공부하려고 합니다. 알파벳이 담긴 배열 spell과 외계어 사전 dic이 매개변수로 주어집니다. spell에 담긴 알파벳을 한번씩만 모두 사용한 단어가 dic에 존재한다면 1, 존재하지 않는다면 2를 return하도록 solution 함수를 완성해주세요.


제한사항

  • spell과 dic의 원소는 알파벳 소문자로만 이루어져있습니다.
  • 2 ≤ spell의 크기 ≤ 10
  • spell의 원소의 길이는 1입니다.
  • 1 ≤ dic의 크기 ≤ 10
  • 1 ≤ dic의 원소의 길이 ≤ 10
  • spell의 원소를 모두 사용해 단어를 만들어야 합니다.
  • spell의 원소를 모두 사용해 만들 수 있는 단어는 dic에 두 개 이상 존재하지 않습니다.
  • dic과 spell 모두 중복된 원소를 갖지 않습니다.

입출력 예

spelldicresult
["p", "o", "s"]["sod", "eocd", "qixm", "adio", "soo"]2
["z", "d", "x"]["def", "dww", "dzx", "loveaw"]1
["s", "o", "m", "d"]["moos", "dzx", "smm", "sunmmo", "som"]2

입출력 예 설명

  • "p", "o", "s" 를 조합해 만들 수 있는 단어가 dic에 존재하지 않습니다. 따라서 2를 return합니다.
  • "z", "d", "x" 를 조합해 만들 수 있는 단어 "dzx"가 dic에 존재합니다. 따라서 1을 return합니다.
  • "s", "o", "m", "d" 를 조합해 만들 수 있는 단어가 dic에 존재하지 않습니다. 따라서 2을 return합니다.

유의사항

  • 입출력 예 #3 에서 "moos", "smm", "som"도 "s", "o", "m", "d" 를 조합해 만들 수 있지만 spell의 원소를 모두 사용해야 하기 때문에 정답이 아닙니다.

나의 풀이

package programmers;

public class AlienDictionary {

	public static int solution(String[] spell, String[] dic) {
        int answer = 0;
        String[] word = new String[dic.length];
        int spellLength = 0;
        
        for (String s :spell) {
        	spellLength += s.length();
        }
        
   
        
        for(int i = 0; i < dic.length; i++) {
           word[i] = dic[i];
           for(String s : spell) {
              word[i] = word[i].replaceFirst(s, "");
           }
           
           if(spellLength == dic[i].length() && word[i].length() == 0) {
        	   answer = 1;
        	   break;
           }else {
        	   answer = 2;
           }
             
        }

        System.out.println(answer);
        return answer;
        }
           
           
   
   public static void main(String[] args) {
      
      String[] spell = {"p", "o", "s"};
      String[] dic = {"sod", "eocd", "qixm", "adio", "soo"};      
      solution(spell, dic);
   }

}

나의 생각

String 배열 dic의 원소 sod,eocd,qixm,adio,soo 중에 spell의 모든 단어를 포함하는 문자가 있으면 return 1 , 아니면 return 2를 하는 문제이다. for문을 dic.length 만큼 반복을 돌려, dic의 원소를 word에 그대로 복사한다. 향상된 for문을 돌려 word[i] = word[i].replaceFirst(s, "") 에 의해 word에 spell의 문자가 포함되면, word의 문자는 빈문자로 치환한다. 예를들어, word = "soo" 라고 할 때, spell의 "s","o"문자를 포함하는데, replaceFirst 메서드를 통해 두개의 o중 하나만 치환되므로, " o" 만 남게된다. 문제에서 spell의 모든 문자가 dic의 원소에 포함되야 하므로 최종적으로 해당 식을 만족해야 문제가 성립된다.

if(spellLength == dic[i].length() && word[i].length() == 0) {
	answer = 1;
    break;
}else {
	answer = 2;
}

spell 의 원소의 크기는 모두 1이고, 해당 식을 이용하여 spell의 전체 길이를 구할 수 있다.

for (String s :spell) {
	spellLength += s.length();
}

따라서, spell원소의 전체 길이와 dic[index].length() 의 길이가 같아야, spell의 원소를 다 포함한다고 할 수 있다. 그리고 && 조건으로 복사된 word[i] 의 원소 " "의 길이가 0이 되야 word[i]의 원소가 모든 spell의 문자를 포함했기때문에 빈문자열로 존재하게 된다.


다른 방법

import java.util.*;

class Solution {
    public int solution(String[] spell, String[] dic) {
        Arrays.sort(spell);

        for (String d : dic) {
            String[] dSplit = d.split("");
            Arrays.sort(dSplit);

            if (Arrays.equals(dSplit, spell)) {
                return 1;
            }
        }

        return 2;
    }
}

풀이법

spell = ["z","d","x"] , dic = ["def","dww","dzx","loveaw"] 일때,

  • Array.sort(spell) 정렬을 통해 spell = ["d","x","z"] 가 된다.
  • dic 배열을 반복문을 실행하여, String[] dSplit = d.split("") 를 통해 현재단어 "def"를 문자 단위로 쪼개어 dSplit 배열에 저장한다.
  • Arrays.sort(dSplit)를 통해 배열을 정렬하여 dSplit = ["d","e","f"]가 된다.
  • if(Arrays.equals(dSplit,spell){ 정렬된 dSplit, spell 배열을 비교한다.
  • 세번째 단어 ["d","x","z"] 와 spell의 ["d","x","z"] 배열의 비교하여 같으므로 return 1이 반환되며, 함수가 종료된다.

profile
HW + SW = 1

0개의 댓글

Powered by GraphCDN, the GraphQL CDN