[JAVA] 알고리즘 문제풀이 기초 - 문자열 part.2
String
중복문자제거 (1-6)
-
설명 : 소문자로 된 한개의 문자열이 입력되면 중복된 문자를 제거하고 출력하는 프로그램을 작성하세요. 중복이 제거된 문자열의 각 문자는 원래 문자열의 순서를 유지합니다.
-
입력 : 첫 줄에 문자열이 입력됩니다. 문자열의 길이는 100을 넘지 않는다.
-
출력 : 첫 줄에 중복문자가 제거된 문자열을 출력합니다.
-
작성답안
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
Main t = new Main();
Scanner scan = new Scanner(System.in);
String str = scan.next();
System.out.println(t.solution(str));
}
public String solution(String word){
char[] ch = word.toCharArray();
String result = String.valueOf(ch[0]);
for (int i=1; i<ch.length; i++){
int num = 0;
for (int j=0; j<i; j++){
if(ch[i]==ch[j]){
num = 1;
}
}
if(num==0){
result += ch[i];
}
}
return String.valueOf(result);
}
}
- 풀이 답안
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
Main t = new Main();
Scanner scan = new Scanner(System.in);
String str = scan.next();
System.out.println(t.solution(str));
}
public String solution(String str){
char[] ch = str.toCharArray();
String result = "";
for(int i=0; i<ch.length; i++){
if(i==str.indexOf(ch[i])){
result += ch[i];
}
}
return result;
}
}
- 특징
- 나의 풀이의 경우 이중 루프를 돌면서 중복 문자가 있는지 체크하고, 해당 단어의 반복이 끝난 후 중복여부가 바뀌지 않은 값만 추가하도록 하였는데
- ‘문자열.indexOf(ch[i])’를 이용해서 해당 문자가 가장 처음 나온 값을 추출하고, 해당 순서가 실제 i일때만 추가하도록 하는편이 훨씬 간편함
- 나의 풀이의 경우 이중 루프를 돌면서 중복 문자가 있는지 체크하고, 해당 단어의 반복이 끝난 후 중복여부가 바뀌지 않은 값만 추가하도록 하였는데
회문 문자열 (1-7)
-
설명 : 앞에서 읽을 때나 뒤에서 읽을 때나 같은 문자열을 회문 문자열이라고 합니다. 문자열이 입력되면 해당 문자열이 회문 문자열이면 “YES”, 회문 문자열이 아니면 “NO”를 출력하는 프로그램을 작성하세요. 단 회문을 검사할 때 대소문자를 구분하지 않습니다.
-
입력 : 첫 줄에 길이 100을 넘지 않는 공백이 없는 문자열이 주어집니다.
-
출력 : 첫 번째 줄에 회문 문자열인지의 결과를 YES 또는 NO로 출력합니다.
-
작성 답안
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
Main t = new Main();
Scanner scan = new Scanner(System.in);
String str = scan.next().toUpperCase();
System.out.println(t.solution(str));
}
public String solution(String word){
char[] ch = word.toCharArray();
int lt=0, rt=word.length()-1;
String result = "YES";
while (lt<rt){
if(!(ch[lt]==ch[rt])){
result = "NO";
break;
}
lt++;
rt--;
}
return result;
}
}
- 풀이 답안-1
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
Main t = new Main();
Scanner scan = new Scanner(System.in);
String str = scan.next().toUpperCase();
System.out.println(t.solution(str));
}
public String solution(String word){
String result = "YES";
char[] ch = word.toCharArray();
for(int i=0; i<word.length()/2; i++){
if(word.charAt(i) != word.charAt((ch.length-1)-i)) {
result = "NO";
break;
}
}
return result;
}
}
- 풀이답안 -2
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
Main t = new Main();
Scanner scan = new Scanner(System.in);
String str = scan.next();
System.out.println(t.solution(str));
}
public String solution(String word){
String result = "YES";
String rv = new StringBuilder(word).reverse().toString();
if(!word.equalsIgnoreCase(rv)) result="NO";
return result;
}
}
- 특징
- 풀이1은 유사한 방식이나 수동으로 lt,rt를 지정하지 않고 idx값으로 계산해서 짧게 풀이. 대소문자는 toUpperCase를 이용해 통일시킴.
- 풀이2는 StringBuilder의 reverse() 메소드를 이용해 문자열을 뒤집은 후, equalsIgnoreCase를 사용해서 대소문자 관계없이 일치하는지 확인
- 풀이1은 유사한 방식이나 수동으로 lt,rt를 지정하지 않고 idx값으로 계산해서 짧게 풀이. 대소문자는 toUpperCase를 이용해 통일시킴.
유효한 팰린드롬 (1-8)
-
설명 : 앞에서 읽을 때나 뒤에서 읽을 때나 같은 문자열을 팰린드롬이라고 합니다. 문자열이 입력되면 해당 문자열이 팰린드롬이면 “YES”, 아니면 “NO”를 출력하는 프로그램을 작성하세요. 단 회문을 검사할 때 알파벳만 가지고 회문을 검사하며, 대소문자를 구분하지 않습니다. 알파벳 이외의 문자들의 무시합니다.
-
입력 : 첫 줄에 길이 100을 넘지 않는 공백이 없는 문자열이 주어집니다.
-
출력 : 첫 번째 줄에 팰린드롬인지의 결과를 YES 또는 NO로 출력합니다.
-
작성 답안
import java.util.Scanner;
import java.util.ArrayList;
public class Main {
public static void main(String[] args) {
Main t = new Main();
Scanner scan = new Scanner(System.in);
String str = scan.nextLine();
System.out.println(t.solution(str));
}
public String solution(String word){
char[] ch = word.toCharArray();
ArrayList str = new ArrayList<>();
for (char c : ch){
if(Character.isAlphabetic(c)){
str.add(Character.toLowerCase(c));
}
}
int lt=0, rt=str.size()-1;
String result = "YES";
while(lt<rt){
if (!str.get(lt).equals(str.get(rt))){
result = "NO";
break;
}
lt++;
rt--;
}
return result;
}
}
- 풀이 답안
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
Main t = new Main();
Scanner scan = new Scanner(System.in);
String str = scan.nextLine();
System.out.println(t.solution(str));
}
public String solution(String word){
String result = "NO";
String str = word.toUpperCase().replaceAll("[^A-Z]", "");
String rv = new StringBuilder(str).reverse().toString();
if(str.equalsIgnoreCase(rv)){
result="YES";
}
return result;
}
}
- 특징
- replaceAll에서는 정규식을 사용할 수 있음.
- toUpperCase()을 사용하여 모두 대문자로 바꿔놓은다음 “^A-Z” 식을 사용해서 A~Z 사이가 아니라면 지움
- replaceAll에서는 정규식을 사용할 수 있음.
숫자만 추출 (1-9)
-
설명 : 문자와 숫자가 섞여있는 문자열이 주어지면 그 중 숫자만 추출하여 그 순서대로 자연수를 만듭니다. 만약 “tge0a1h205er”에서 숫자만 추출하면 0, 1, 2, 0, 5이고 이것을 자연수를 만들면 1205이 됩니다. 추출하여 만들어지는 자연수는 100,000,000을 넘지 않습니다.
-
입력 : 첫 줄에 숫자가 섞인 문자열이 주어집니다. 문자열의 길이는 100을 넘지 않습니다.
-
출력 : 첫 줄에 자연수를 출력합니다.
-
작성 답안 -1
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
Main t = new Main();
Scanner scan = new Scanner(System.in);
String str = scan.next();
System.out.println(t.solution(str));
}
public int solution(String word){
char[] ch = word.toCharArray();
String result = "";
for(int i=0; i<ch.length; i++){
if(Character.isDigit(ch[i])){
result += ch[i];
}
}
return Integer.parseInt(result);
}
}
- 작성답안-2
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
Main t = new Main();
Scanner scan = new Scanner(System.in);
String str = scan.next();
System.out.println(t.solution(str));
}
public int solution(String word){
char[] ch = word.toCharArray();
String result = "";
for(int i=0; i<ch.length; i++){
if(Character.isDigit(ch[i])){
result += ch[i];
}
}
return Integer.parseInt(result);
}
}
- 특징
- Character.isDigit(char형) 을 사용하여 전체배열에서 숫자만 추출하는 방식으로 풀이함
- 앞서 배운 replaceAll 정규식을 사용하여 숫자가 아닌 항목들을 모두 지움
- Character.isDigit(char형) 을 사용하여 전체배열에서 숫자만 추출하는 방식으로 풀이함
가장 짧은 문자거리 (1-10)
-
설명 : 한 개의 문자열 s와 문자 t가 주어지면 문자열 s의 각 문자가 문자 t와 떨어진 최소거리를 출력하는 프로그램을 작성하세요.
-
입력 : 첫 번째 줄에 문자열 s와 문자 t가 주어진다. 문자열과 문자는 소문자로만 주어집니다. 문자열의 길이는 100을 넘지 않는다.
-
출력 : 첫 번째 줄에 각 문자열 s의 각 문자가 문자 t와 떨어진 거리를 순서대로 출력한다.
-
작성 답안
import java.util.ArrayList;
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
Main t = new Main();
Scanner scan = new Scanner(System.in);
String str = scan.next();
char ch = scan.next().charAt(0);
int[] result = t.solution(str, ch);
for (int i : result) {
System.out.print(i+" ");
}
}
public int[] solution(String word, char ch){
int[] result = new int[word.length()];
char[] _ch = word.toCharArray();
ArrayList<Integer> state = new ArrayList<>();
for(int i=0; i<word.length(); i++){
if(_ch[i]==ch){
state.add(i);
}
}
for(int i=0; i<word.length(); i++){
for (Integer integer : state) {
if(_ch[i]!=ch && (result[i]==0 || result[i]>Math.abs(i-integer))){
result[i] = Math.abs(i-integer);
}
}
}
return result;
}
}
- 풀이 답안
import java.util.ArrayList;
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
Main t = new Main();
Scanner scan = new Scanner(System.in);
String str = scan.next();
char ch = scan.next().charAt(0);
int[] result = t.solution(str, ch);
for (int i : result) {
System.out.print(i+" ");
}
}
public int[] solution(String word, char ch){
int[] result = new int[word.length()];
char[] _ch = word.toCharArray();
int len = 1000;
for(int i=0; i<word.length(); i++){
if(_ch[i]==ch){
len = 0;
result[i] = len;
} else {
result[i] = len;
}
len++;
}
len = 10000;
for(int i=word.length()-1; i>=0; i--){
if(_ch[i]==ch){
len = 0;
} else if (result[i]>len){
result[i] = len;
}
len++;
}
return result;
}
}
- 특징
- 나의 풀이의 경우 ch의 idx를 먼저 구하고, 이중 루프를 통해 해당 idx와 현재 idx의 차이를 바로 대입하였음. Math.abs(i-integer)를 통해 절대값을 적용하고, 조건문에 현재 절대값과 이미 적용된 값을 비교해 더 작을때만 반영되도록 함
- 배열 하나를 양방향으로 읽는 방식으로 해, 앞전보다 작은 값일때만 반영되게 함
- 최초에는 임의의값 1000을 적용하고 대응할 ch를 만났을때 0으로 리셋, 그 이후로는 한칸 이동시 ++ 하는 방식
- 나의 풀이의 경우 ch의 idx를 먼저 구하고, 이중 루프를 통해 해당 idx와 현재 idx의 차이를 바로 대입하였음. Math.abs(i-integer)를 통해 절대값을 적용하고, 조건문에 현재 절대값과 이미 적용된 값을 비교해 더 작을때만 반영되도록 함
문자열 압축 (1-11)
-
설명 : 알파벳 대문자로 이루어진 문자열을 입력받아 같은 문자가 연속으로 반복되는 경우 반복되는 문자 바로 오른쪽에 반복 횟수를 표기하는 방법으로 문자열을 압축하는 프로그램을 작성하시오. 단 반복횟수가 1인 경우 생략합니다.
-
입력 : 첫 줄에 문자열이 주어진다. 문자열의 길이는 100을 넘지 않는다.
-
출력 : 첫 줄에 압축된 문자열을 출력한다.
-
작성 답안
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
Main t = new Main();
Scanner scan = new Scanner(System.in);
String str = scan.next();
System.out.print(t.solution(str));
}
public String solution(String word){
String result = String.valueOf(word.charAt(0));
int cnt = 1;
for(int i=1; i<word.length(); i++){
if(word.charAt(i-1)!=word.charAt(i)){
if(cnt!=1){
result += cnt;
}
result += word.charAt(i);
cnt = 1;
} else {
cnt++;
}
}
if(cnt!=1){
result += cnt;
}
return result;
}
}
- 특징
- 현재의 문자열을 대입하고, 앞선 문자열과 달라졌을때 cnt 수가 증가되어있는 상태라면 현재의 문자열을 대입하기 전 cnt숫자도 반환값에 대입해줌 (풀이도 비슷한 방식이라 추가하지 않음)
- 현재의 문자열을 대입하고, 앞선 문자열과 달라졌을때 cnt 수가 증가되어있는 상태라면 현재의 문자열을 대입하기 전 cnt숫자도 반환값에 대입해줌 (풀이도 비슷한 방식이라 추가하지 않음)
암호 (1-12)
- 설명 : 현수는 영희에게 알파벳 대문자로 구성된 비밀편지를 매일 컴퓨터를 이용해 보냅니다. 비밀편지는 현수와 영희가 서로 약속한 암호로 구성되어 있습니다. 비밀편지는 알파벳 한 문자마다 # 또는 *이 일곱 개로 구성되어 있습니다. 만약 현수가 “#*****#”으로 구성된 문자를 보냈다면 영희는 현수와 약속한 규칙대로 다음과 같이 해석합니다.
- “#*****#”를 일곱자리의 이진수로 바꿉니다. #은 이진수의 1로, *이진수의 0으로 변환합니다. 결과는 “1000001”로 변환됩니다.
- 바뀐 2진수를 10진수화 합니다. “1000001”을 10진수화 하면 65가 됩니다.
- 아스키 번호가 65문자로 변환합니다. 즉 아스크번호 65는 대문자 ‘A’입니다. 참고로 대문자들의 아스키 번호는 ‘A’는 65번, ‘B’는 66번, ’C’는 67번 등 차례대로 1씩 증가하여 ‘Z’는 90번입니다. 현수가 4개의 문자를 다음과 같이 신호로 보냈다면 #**###**#####**#####**##** 이 신호를 4개의 문자신호로 구분하면
- “#*****#”를 일곱자리의 이진수로 바꿉니다. #은 이진수의 1로, *이진수의 0으로 변환합니다. 결과는 “1000001”로 변환됩니다.
#****## –> ‘C’
#**#### –> ‘O’
#**#### –> ‘O’
#**##** –> ‘L’
최종적으로 “COOL”로 해석됩니다. 현수가 보낸 신호를 해석해주는 프로그램을 작성해서 영희를 도와주세요.
-
입력 : 첫 줄에는 보낸 문자의 개수(10을 넘지 안습니다)가 입력된다. 다음 줄에는 문자의 개수의 일곱 배 만큼의 #또는 * 신호가 입력됩니다. 현수는 항상 대문자로 해석할 수 있는 신호를 보낸다고 가정합니다.
-
출력 : 영희가 해석한 문자열을 출력합니다
-
작성 답안
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
Main t = new Main();
Scanner scan = new Scanner(System.in);
Integer num = scan.nextInt();
String str = scan.next();
System.out.print(t.solution(str, num));
}
public String solution(String str, int num){
char[] word = str.toCharArray();
String[] nums = new String[num];
String result = "";
for(int i=0; i<str.length(); i++){
if(i%7==0){
if(word[i]=='#') nums[i/7] = "1" ;
else if(word[i]=='*') nums[i/7] = "0" ;
} else {
if(word[i]=='#') nums[i/7] += "1" ;
else if(word[i]=='*') nums[i/7] += "0" ;
}
}
for (String s : nums) {
char r = (char) Integer.parseInt(s, 2);
result += r;
}
return result;
}
}
- 풀이 답안
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
Main t = new Main();
Scanner scan = new Scanner(System.in);
Integer num = scan.nextInt();
String str = scan.next();
System.out.print(t.solution(str, num));
}
public String solution(String str, int num){
String result = "";
for(int i=0; i<num; i++){
String tmp = str.substring(0,7).replace('#','1').replace('*', '0');
str = str.substring(7);
int n = Integer.parseInt(tmp, 2);
result += (char) n;
}
return result;
}
}
- 특징
- 내 풀이의 경우 7로 나누는 작업과 조건문을 통해 일일히 비교후 변경하는 하드 코딩을 진행하고, 그 후 다시 반복을 통해 각 숫자들을 10진수로 변경해 단어로 바꾸는 작업을 진행함
- 풀이에서는 substring을 통해 원하는 범위만큼을 잘라내고, 기존 문자열을 다시 한번 substring으로 잘라 이후범위부터 작업할수 있도록 함
- 문자열 변경 역시 replace함수를 통해 한번에 진행함
- 또 10진수 변경과, 반환 문자열 대입까지 반복문 한번에 모두 진행할수 있게 함
- 내 풀이의 경우 7로 나누는 작업과 조건문을 통해 일일히 비교후 변경하는 하드 코딩을 진행하고, 그 후 다시 반복을 통해 각 숫자들을 10진수로 변경해 단어로 바꾸는 작업을 진행함