* 문제 풀이에 중점을 두었기에, 파일입력처리 & 에러처리 & 비~자바적 표현(?)등은 무시해주시기 바랍니다. 그리고 귀찮아서 온통 public static으로 도배하였으니 양해바랍니다. ^^; 이 문제들을 풀면서 가장 어려웠던 점은 역시나~ 변수 이름, 메소드 이름짓기였습니다. ^^;;;
이 풀이들이 정상적인 풀이인지는 본인도 모릅니다. 샘플 데이터에 대한 결과는 동일한데, 데이터가 달라지면 엉뚱한 결과가 나타날지도 모르니 유의해주시기 바랍니다.
그리고 좀 더 나은 풀이 방법이나 다른 풀이 방법이 있으면 알려주시면 감사하겠습니다. 다양한 시각을 가지고 싶은 욕망에, 쪽팔림을 무릅쓰고 올린 소스이니, 많은 참여(?) 부탁드립니다. ^^;
프로그래머는 코드~로 말한다는 이념아래, 설명은 생략하겠습니다. --;
문제 출처 : http://synap.tistory.com/214
Q1. 도형을 찾아라.
- 도형이 뭔지 몰라서 조금 헤메였던 문제인데, 본인은 해당 점이 속한 줄(level)의 시작 점, 끝점을 계산해낸다음, 각 점들의 상대적인 길이를 추출한후 비교하는식으로 처리하였다. 처음 생각은 시작 점, 끝점을 따로(?) 계산할려고 했으나, 끝점만 구하면 나머지는 자동(?)이라서 한결 편한게 처리했다. 끝점을 구하는방법은 뭐 단순무식하게 더하는것이다. ^^;
- 뭐 나머지는, 입력받은 점들을 정리(?)한다음 각 점들 사이의 길이를 구해서 동일한지 검사하면 되는것이다. 혹시 점들 사이가 직선이 아닐 경우는 에러를 발생시켜 도형이 아니라고 판단하게 하였다.
- 전체 소스
Q2. 문자를 보내자.
- 너무 단순해서 설명할게 없음 ^^;
Q3. 3개의 제곱
- 단순히 주어진 계산식에 의한 값을 비교했을뿐이고~
- 자바에서는 int[] numbers = new int[3]; 선언하면 각 int 값들이 0으로 초기화되므로 0의제곱은 자연스럽게 해결되어버리고, 제곱근은 자바의 Math.sqrt() 함수를 사용했기에, 간단히 해결 ^^;
Q4. 이진수 곱하기.
- 가장 어려웠던 문제가 아닐까 싶다.
- 인간과 컴의 차이에서 오는 곱하기 방법에 대한 고찰(?)을 해보려했으나, 머리가 아파서, 계산하는것처럼 보여주는것으로 결론을 내려버림. 그래서 계산따로~ 결과따로인 프로그램이 되어버렸지만, 결과는 제대로 나오는것 같음 ^^;
Q5. Triples
- 단순히 주어진 계산식에 의한 값을 비교했을뿐이고~
- 어쩌다 for문을 열심히 돌렸을 뿐인데~ 해결된 문제.
Q6. 막대 자르기
- 이 문제를 본 순간 생각나는게 최소공배수, 최대공약수였다. 사실 최소공배수, 최대공약수와 전혀 상관이 없고, 최소공배수, 최대공약수가 뭔지 기억도 안나지만, 왠지 뉘앙스~가 그렇고 그런것 같은 느낌이 들어서 단지~ 나눠(?)봤더니 해결된거 같다. ^^; 나눠진 막대들의 총 합을 구한다음, 가장 큰 막대의 길이로 나눌때 그 나머지가 0일 경우, 나눠진 막대기들이 그 길이에 합체가 가능한지 판단하였다.
Q7. 문장 비교
- 초점은 어디에 두느냐에 따라 풀이과정이 틀려지는 문제인데, 본인은 문자 비교보다는 단어 비교에 중점을 두었다.
- 구분자를 공백(" ")과 마침표(.)로 단어를 추출한 후 비교하였는데, 현재 구현상에서는 구분자도 단어로 인식(?)하는 문제점이 있어서 수정을 해야하지만, 귀찮아서 패스~. ^^;
- 처음는 대용량(?) 처리를 위해 토큰을 나누는 부분을 별도의 클래스로 분리해서 만들려고 했으니, 게으름병이도져서, 메모리상에서 그냥 나눠버림. ^^;
- 넋두리
: 개발자라면 당연히 논리적인 사고능력으로 문제를 해결해야하는데, 불행히도 본인은 그렇게 하지 못한다. 본인은 엉성한 직관력과 실험(?)&관찰(?)로 문제를 해결(쉽게 말해서 찍는다. ^^;)하는데, 아직까지 큰 사고(?)없이 지내온게 신기할따름이다. ^^; 위의 문제들도 대부분 찍어서(?) 푼것들인데, 틀렸다면 어쩔수 없고, 맞았다면 잘 찍은것일뿐이다. ^^; 본인에게 필요한건, 일어날 수 있는 모든수의 테스트 데이터뿐~~~~ ^^;;;;;
: 이자리를 빌어서 재미있는 문제를 던져~주신 사이냅소프트에게 감사의 인사를 ^^
Q6. 막대 자르기 코드에 문제가 있었다. 막대기 합체 로직이 잘못되어서 제대로 계산을 못하는 문제인데, 땜빵으로 수정을 해놨지만, 이것도 정상적으로 작동하리라는 보장이 없으니... 쿨럭... ^^;
기존에는 큰수부터 더해나가서 해당 막대기의 길이에 부합하는지 판단했는데, "큰수" + "큰수 다음의 수" 이렇게 계산이 일어나서, "큰수 다음의 수"가 목적에 부합하지 않을 경우 그 다음의 수부터 계산하는 로직이 빠져있어서, 특정 숫자에서 꽥하는 성질을 발견하여서 수정한것이다. 사실 수정한 코드도 자신이 없는관계로... 누가 한번 정리해주셨으면 감사~감사~ ^^;
- 기존 코드
- 변경 후 코드
Q1. 도형을 찾아라.
옆에분(?)이 푼거랑 비교를 해보니, 전체적인 개념(?)은 비슷한거 같고 눈에 띄는 한가지. 본인은 끝점을 무식하게 더했는데, 한줄로 표현해주시는 센스~~
이 풀이들이 정상적인 풀이인지는 본인도 모릅니다. 샘플 데이터에 대한 결과는 동일한데, 데이터가 달라지면 엉뚱한 결과가 나타날지도 모르니 유의해주시기 바랍니다.
그리고 좀 더 나은 풀이 방법이나 다른 풀이 방법이 있으면 알려주시면 감사하겠습니다. 다양한 시각을 가지고 싶은 욕망에, 쪽팔림을 무릅쓰고 올린 소스이니, 많은 참여(?) 부탁드립니다. ^^;
프로그래머는 코드~로 말한다는 이념아래, 설명은 생략하겠습니다. --;
문제 출처 : http://synap.tistory.com/214
Q1. 도형을 찾아라.
- 도형이 뭔지 몰라서 조금 헤메였던 문제인데, 본인은 해당 점이 속한 줄(level)의 시작 점, 끝점을 계산해낸다음, 각 점들의 상대적인 길이를 추출한후 비교하는식으로 처리하였다. 처음 생각은 시작 점, 끝점을 따로(?) 계산할려고 했으나, 끝점만 구하면 나머지는 자동(?)이라서 한결 편한게 처리했다. 끝점을 구하는방법은 뭐 단순무식하게 더하는것이다. ^^;
/**
* <p>해당 라인의 마지막 점 위치를 가져온다.</p>
*
* @param level
* @return
*/
protected static int getEndPoint(int level) {
int k = 0;
int n = 0;
for (int i = 0; i < level; i++) {
k = k + 1;
n = n + k;
}
return n;
}
- 주어진 조건에서 나올 수 있는 조건은 정삼각형, 평행사변형, 육각형밖에 없는거 같아서, 아래처럼 하드코딩(?)을 하였는데, 점들의 순서만 잘 정리하면 좀 더 이쁘게 구현 할 수 있을거 같았지만, 귀찮아서 패스. int[] lineLen = new int[numbers.length];
if (numbers.length == 3) {
lineLen[0] = getLength(points[0], points[1]);
lineLen[1] = getLength(points[1], points[2]);
lineLen[2] = getLength(points[2], points[0]);
return isSameLength(lineLen);
} else if (numbers.length == 4) {
if (points[0].level == points[1].level) {
lineLen[0] = getLength(points[0], points[1]);
lineLen[1] = getLength(points[1], points[3]);
lineLen[2] = getLength(points[3], points[2]);
lineLen[3] = getLength(points[2], points[1]);
return isSameLength(lineLen);
} else {
lineLen[0] = getLength(points[0], points[2]);
lineLen[1] = getLength(points[2], points[3]);
lineLen[2] = getLength(points[3], points[1]);
lineLen[3] = getLength(points[1], points[0]);
return isSameLength(lineLen);
}
} else if (numbers.length == 6) {
if (points[0].level == points[1].level) {
lineLen[0] = getLength(points[0], points[1]);
lineLen[1] = getLength(points[1], points[3]);
lineLen[2] = getLength(points[3], points[5]);
lineLen[3] = getLength(points[5], points[4]);
lineLen[4] = getLength(points[4], points[2]);
lineLen[5] = getLength(points[2], points[0]);
return isSameLength(lineLen);
} else {
return true;
}
}
- 뭐 나머지는, 입력받은 점들을 정리(?)한다음 각 점들 사이의 길이를 구해서 동일한지 검사하면 되는것이다. 혹시 점들 사이가 직선이 아닐 경우는 에러를 발생시켜 도형이 아니라고 판단하게 하였다.
- 전체 소스
package synap;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintStream;
import java.util.StringTokenizer;
/**
* <p>Q1. 도형을 찾아라.</p>
*
* @author kangwoo
*
*/
public class Answer1 {
public static void main(String[] args) throws Exception {
String filename = "q1_input.txt";
BufferedReader reader = null;
try {
reader = new BufferedReader(new InputStreamReader(Answer1.class.getResourceAsStream(filename)));
String line = null;
while ( (line = reader.readLine()) != null) {
int[] numbers = parseNumbers(line);
printIsFigure(numbers, System.out);
}
} finally {
if (reader != null) try {reader.close();} catch(IOException ie) {}
}
}
/**
* <p>공백으로 분리된 숫자들을 나눠서, 숫자 배열로 변현환한다.</p>
*
* @param line
* @return
* @throws NumberFormatException
*/
public static int[] parseNumbers(String line) throws NumberFormatException {
if (line == null || line.trim() == "") {
return null;
}
StringTokenizer st = new StringTokenizer(line.trim(), " ");
int[] numbers = new int[st.countTokens()];
for (int i = 0; st.hasMoreTokens(); i++) {
numbers[i] = Integer.parseInt(st.nextToken());
}
return numbers;
}
/**
* <p>해당 점들로 이루어진 도형이 구성가능한지 판단하여 결과를 출력한다.</p>
*
* @param numbers 점들
* @param out 출력할 대상
*/
public static void printIsFigure(int[] numbers, PrintStream out) {
StringBuilder sb = new StringBuilder();
if (numbers != null) {
for (int i = 0; i < numbers.length; i++) {
if (i > 0) {
sb.append(" ");
}
sb.append(numbers[i]);
}
}
if (isFigure(numbers)) {
sb.append(" are the vertices of ");
if (numbers.length == 3) {
sb.append("a triangle");
} else if (numbers.length == 4) {
sb.append("a parallelogram");
} else if (numbers.length == 6) {
sb.append("a hexagon");
}
} else {
sb.append(" are not the vertices of an acceptable figure");
}
out.println(sb.toString());
}
/**
* <p>해당 점들로 이루어진 도형이 구성가능한지 판단한다.</p>
*
* @param numbers
* @return
*/
public static boolean isFigure(int[] numbers) {
if (numbers == null || (numbers.length != 3 && numbers.length != 4 && numbers.length != 6)) {
return false;
}
Point[] points = new Point[numbers.length];
for (int i = 0; i < points.length; i++) {
points[i] = getPoint(numbers[i]);
}
// 정렬
for (int i = 0; i < points.length; i++) {
for (int j = 0; j < points.length; j++) {
if (points[i].compareTo(points[j]) > 0) {
Point temp = points[i];
points[i] = points[j];
points[j] = temp;
}
}
}
try {
int[] lineLen = new int[numbers.length];
if (numbers.length == 3) {
lineLen[0] = getLength(points[0], points[1]);
lineLen[1] = getLength(points[1], points[2]);
lineLen[2] = getLength(points[2], points[0]);
return isSameLength(lineLen);
} else if (numbers.length == 4) {
if (points[0].level == points[1].level) {
lineLen[0] = getLength(points[0], points[1]);
lineLen[1] = getLength(points[1], points[3]);
lineLen[2] = getLength(points[3], points[2]);
lineLen[3] = getLength(points[2], points[1]);
return isSameLength(lineLen);
} else {
lineLen[0] = getLength(points[0], points[2]);
lineLen[1] = getLength(points[2], points[3]);
lineLen[2] = getLength(points[3], points[1]);
lineLen[3] = getLength(points[1], points[0]);
return isSameLength(lineLen);
}
} else if (numbers.length == 6) {
if (points[0].level == points[1].level) {
lineLen[0] = getLength(points[0], points[1]);
lineLen[1] = getLength(points[1], points[3]);
lineLen[2] = getLength(points[3], points[5]);
lineLen[3] = getLength(points[5], points[4]);
lineLen[4] = getLength(points[4], points[2]);
lineLen[5] = getLength(points[2], points[0]);
return isSameLength(lineLen);
} else {
return true;
}
}
} catch (IllegalArgumentException e) {
return false;
}
return true;
}
/**
* <p>각 길이들이 동일한 길이인지 검사한다.</p>
*
* @param lengths 길이들
* @return
*/
protected static boolean isSameLength(int[] lengths) {
if (lengths == null || lengths.length < 2) {
return false;
}
for (int i = 1; i < lengths.length; i++) {
if (lengths[0] != lengths[i]) {
return false;
}
}
return true;
}
/**
* <p>두 점사이의 위치를 계산한다. 두점사이가 직선이 아닐경우 에러가 발생한다.</p>
*
* @param x
* @param y
* @return 두 점으로 이루어진 직선의 길이
* @throws IllegalArgumentException 두점사이가 직선이 아닐경우 발생
*/
protected static int getLength(Point x, Point y) {
Point tX, tY;
if (x.compareTo(y) > 0) {
tX = y;
tY = x;
} else {
tX = x;
tY = y;
}
if (tX.level == tY.level) {
return tY.currentPoint - tX.currentPoint;
} else {
int beginDiff = tX.currentPoint - tX.beginPoint;
int endDiff = tX.endPoint - tX.currentPoint;
if (tY.currentPoint == (tY.endPoint - endDiff)
|| tY.currentPoint == (tY.beginPoint + beginDiff)) {
return tY.level - tX.level;
}
throw new IllegalArgumentException("입력한 두개의 점(" + x + ", " + y + ")으로는 한 변을 만들 수 없습니다.");
}
}
/**
* <p>점의 위치, 해당라인의 시작위치와, 마지막위치, 레벨을 계산한다.</p>
*
* @param x
* @return
*/
protected static Point getPoint(int x) {
int endPoint = 0;
for (int i = 1; i < Integer.MAX_VALUE; i++) {
endPoint = getEndPoint(i);
if (x <= endPoint) {
int level = i;
int beginPoint = getBeginPoint(level, endPoint);
return new Point(level, beginPoint, x, endPoint);
}
}
return null;
}
protected static int getBeginPoint(int level, int endPoint) {
return endPoint - (level - 1);
}
/**
* <p>해당 라인의 마지막 점 위치를 가져온다.</p>
*
* @param level
* @return
*/
protected static int getEndPoint(int level) {
int k = 0;
int n = 0;
for (int i = 0; i < level; i++) {
k = k + 1;
n = n + k;
}
return n;
}
/**
* 점의 위치(해당 레벨의 시작 위치, 끝 위치)를 나타내는 클래스
* @author kangwoo
*
*/
static class Point implements Comparable<Point> {
int level;
int beginPoint;
int currentPoint;
int endPoint;
Point(int level, int beginPoint, int currentPoint, int endPoint) {
this.level = level;
this.beginPoint = beginPoint;
this.currentPoint = currentPoint;
this.endPoint = endPoint;
}
public int compareTo(Point another) {
return currentPoint - another.currentPoint;
}
@Override
public String toString() {
return String.valueOf(currentPoint);
}
}
}
Q2. 문자를 보내자.
- 너무 단순해서 설명할게 없음 ^^;
package synap;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintStream;
/**
* <p>Q2. 문자를 보내자.</p>
*
* @author kangwoo
*
*/
public class Answer2 {
private static char[][] keypads = {
{'a', 'b', 'c'}, {'d', 'e', 'f'}, {'g', 'h', 'i'},
{'j', 'k', 'l'}, {'m', 'n', 'o'}, {'p', 'q', 'r', 's'},
{'t', 'u', 'v'}, {'w', 'x', 'y', 'z'}, {' '}};
public static void main(String[] args) throws Exception {
String filename = "q2_input.txt";
BufferedReader reader = null;
try {
reader = new BufferedReader(new InputStreamReader(Answer2.class.getResourceAsStream(filename)));
String line = reader.readLine();
int lineCount = Integer.parseInt(line);
String[] lines = new String[lineCount];
for (int i = 0; i < lineCount;i ++) {
lines[i] = reader.readLine();
printPressCount(lines[i], i + 1, System.out);
}
} finally {
if (reader != null) try {reader.close();} catch(IOException ie) {}
}
}
/**
* <p>해당 문자열를 입력하기 위해 필요한 총 입력 회수를 출력한다.</p>
*
* @param str 문자열
* @param index Case 순서
* @param out 출력대상
*/
public static void printPressCount(String str, int index, PrintStream out) {
int count = getPressCount(str);
StringBuilder sb = new StringBuilder();
sb.append("Case #").append(index);
sb.append(": ").append(count);
out.println(sb.toString());
}
/**
* <p>해당 문자열를 입력하기 위해 필요한 총 입력 회수를 계산한다.</p>
*
* @param str 문자열
* @return 총 입력 회수
*/
public static int getPressCount(String str) {
int count = 0;
if (str != null) {
char[] charArray = str.toCharArray();
for (char c : charArray) {
count += getPressCount(c);
}
}
return count;
}
/**
* <p>해당 문자를 입력하기 위해 필요한 입력 회수를 계산한다.</p>
*
* @param c 문자
* @return 입력 회수
*/
public static int getPressCount(char c) {
for (int i = keypads.length - 1; i >= 0; i--) {
for (int j = 0; j < keypads[i].length; j++) {
if (c == keypads[i][j]) {
return j + 1;
} else if (c < keypads[i][j]) {
break;
}
}
}
throw new RuntimeException("\"" + c + "\" 문자는 처리할 수 없는 문자입니다.");
}
}
Q3. 3개의 제곱
- 단순히 주어진 계산식에 의한 값을 비교했을뿐이고~
- 자바에서는 int[] numbers = new int[3]; 선언하면 각 int 값들이 0으로 초기화되므로 0의제곱은 자연스럽게 해결되어버리고, 제곱근은 자바의 Math.sqrt() 함수를 사용했기에, 간단히 해결 ^^;
package synap;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
/**
* <p>Q3. 3개의 제곱.</p>
*
* @author kangwoo
*
*/
public class Answer3 {
public static void main(String[] args) throws Exception {
String filename = "q3_input.txt";
BufferedReader reader = null;
try {
reader = new BufferedReader(new InputStreamReader(Answer3.class.getResourceAsStream(filename)));
String line = reader.readLine();
int lineCount = Integer.parseInt(line);
String[] lines = new String[lineCount];
for (int i = 0; i < lineCount;i ++) {
lines[i] = reader.readLine();
System.out.println(getFermat(Integer.parseInt(lines[i].trim())));
}
} finally {
if (reader != null) try {reader.close();} catch(IOException ie) {}
}
}
/**
* <p>주어진 숫자 k가 3개의 자연수(0을 포함)의 제곱으로 표현될 수 있다면, 그 3개의 수를 출력하고, 불가능하다면 -1을 출력한다.</p>
*
* @param k 자연수
* @return
*/
public static String getFermat(int k) {
int[] numbers = new int[3];
int remainK = k;
for (int i = numbers.length - 1 ; i >= 0; i--) {
int square = (int)Math.sqrt(remainK);
numbers[i] = square;
remainK = remainK - (square * square);
}
if (remainK > 0) {
return "-1";
} else {
StringBuilder sb = new StringBuilder();
for (int i = 0; i < numbers.length; i++) {
if (i > 0) {
sb.append(" ");
}
sb.append(numbers[i]);
}
return sb.toString();
}
}
}
Q4. 이진수 곱하기.
- 가장 어려웠던 문제가 아닐까 싶다.
- 인간과 컴의 차이에서 오는 곱하기 방법에 대한 고찰(?)을 해보려했으나, 머리가 아파서, 계산하는것처럼 보여주는것으로 결론을 내려버림. 그래서 계산따로~ 결과따로인 프로그램이 되어버렸지만, 결과는 제대로 나오는것 같음 ^^;
package synap;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
/**
* <p>Q4. 이진수 곱하기.</p>
* @author kangwoo
*
*/
public class Answer4 {
public static void main(String[] args) throws Exception {
String filename = "q4_input.txt";
BufferedReader reader = null;
try {
reader = new BufferedReader(new InputStreamReader(Answer4.class.getResourceAsStream(filename)));
String line = null;
while ( (line = reader.readLine()) != null) {
if ("0 0".equals(line.trim())) {
break;
}
String[] binArray = line.split(" ");
System.out.println(multiple(binArray[0], binArray[1]));
System.out.println();
}
} finally {
if (reader != null) try {reader.close();} catch(IOException ie) {}
}
}
/**
* <p>두 이진수를 곱한다.</p>
* @param xStr 이진수 문자열
* @param yStr 이진수 문자열
* @return
*/
public static String multiple(String xStr, String yStr) {
int x = Integer.parseInt(xStr, 2);
int y = Integer.parseInt(yStr, 2);
int z = x * y;
StringBuilder sb = new StringBuilder();
String zStr = Integer.toBinaryString(z);
int maxLen = zStr.length();
sb.append(leftPad(Integer.toBinaryString(x), maxLen, " ")).append("\n");
sb.append(leftPad(Integer.toBinaryString(y), maxLen, " ")).append("\n");
sb.append(leftPad(repeat("-", (xStr.length() > yStr.length() ? xStr.length() : yStr.length())), maxLen, " ")).append("\n");
for (int i = 0; i < yStr.length(); i++) {
sb.append(leftPad(leftPad(Integer.toBinaryString(x * ((y >> i) & 1)), xStr.length(), "0"), maxLen - i, " "));
for (int j = 0; j < i; j++) {
sb.append(" ");
}
sb.append("\n");
}
sb.append(repeat("-", maxLen)).append("\n");
sb.append(zStr);
return sb.toString();
}
/**
* <p>왼쪽부터 크기만큼 문자열로 채워준다.</p>
*
* @param str
* @param size
* @param padStr
* @return
*/
public static String leftPad(String str, int size, String padStr) {
if (str == null) {
return null;
}
if (padStr == null) {
return str;
}
int strLen = str.length();
int padStrLen = padStr.length();
int padLen = size - strLen;
if (padLen <= 0) {
return str;
}
StringBuilder result = new StringBuilder();
if (padLen == padStrLen) {
result.append(padStr);
result.append(str);
} else if (padLen < padStrLen) {
result.append(padStr.substring(0, padLen));
result.append(str);
} else {
char[] padding = padStr.toCharArray();
for (int i = 0; i < padLen; i++) {
result.append(padding[ i % padStrLen]);
}
result.append(str);
}
return result.toString();
}
/**
* <p>회수만큼 문자열을 반복시킨다.</p>
*
* @param str
* @param repeat
* @return
*/
public static String repeat(String str, int repeat) {
if (str == null) {
return null;
}
if (repeat < 1) {
return "";
}
int inputLen = str.length();
if (inputLen == 0 || repeat == 1) {
return str;
}
int outputLen = inputLen * repeat;
if (inputLen == 1) {
char ch = str.charAt(0);
char[] output = new char[outputLen];
for (int i = 0; i < outputLen; i++) {
output[i] = ch;
}
return new String(output);
} else {
StringBuilder output = new StringBuilder(outputLen);
for (int i = 0; i < repeat; i++) {
output.append(str);
}
return output.toString();
}
}
}
Q5. Triples
- 단순히 주어진 계산식에 의한 값을 비교했을뿐이고~
- 어쩌다 for문을 열심히 돌렸을 뿐인데~ 해결된 문제.
package synap;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
public class Answer5 {
public static void main(String[] args) throws Exception {
String filename = "q5_input.txt";
BufferedReader reader = null;
try {
reader = new BufferedReader(new InputStreamReader(Answer5.class.getResourceAsStream(filename)));
String line = null;
while ( (line = reader.readLine()) != null && !line.trim().equals("0")) {
int numCount = Integer.parseInt(line);
String[] numberStr = reader.readLine().split(" ");
int[] numbers = new int[numCount];
for (int i = 0; i < numCount;i ++) {
numbers[i] = Integer.parseInt(numberStr[i]);
}
System.out.println(getTripleCount(numbers));
}
} finally {
if (reader != null) try {reader.close();} catch(IOException ie) {}
}
}
/**
* <p>Triple 개수룰 가져온다.</p>
*
* @param numbers
* @return
*/
public static int getTripleCount(int[] numbers) {
int count = 0;
for (int i = 0; i < numbers.length; i++) {
for (int j = i + 1; j < numbers.length; j++) {
for (int k = 0; k < numbers.length; k++) {
if (i != k && j != k) {
if (isTriple(numbers[i], numbers[j], numbers[k])) {
count++;
}
}
}
}
}
return count;
}
/**
* <p>x + y = z 인지 판단한다.</p>
*
* @param x
* @param y
* @param z
* @return
*/
public static boolean isTriple(int x, int y, int z) {
return x + y == z;
}
}
Q6. 막대 자르기
- 이 문제를 본 순간 생각나는게 최소공배수, 최대공약수였다. 사실 최소공배수, 최대공약수와 전혀 상관이 없고, 최소공배수, 최대공약수가 뭔지 기억도 안나지만, 왠지 뉘앙스~가 그렇고 그런것 같은 느낌이 들어서 단지~ 나눠(?)봤더니 해결된거 같다. ^^; 나눠진 막대들의 총 합을 구한다음, 가장 큰 막대의 길이로 나눌때 그 나머지가 0일 경우, 나눠진 막대기들이 그 길이에 합체가 가능한지 판단하였다.
package synap;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.List;
/**
* <p>Q6. 막대 자르기</p>
*
* @author kangwoo
*
*/
public class Answer6 {
public static void main(String[] args) throws Exception {
String filename = "q6_input.txt";
BufferedReader reader = null;
try {
reader = new BufferedReader(new InputStreamReader(Answer6.class.getResourceAsStream(filename)));
String line = null;
while ( (line = reader.readLine()) != null && !line.trim().equals("0")) {
int numCount = Integer.parseInt(line);
String[] numberStr = reader.readLine().split(" ");
int[] numbers = new int[numCount];
for (int i = 0; i < numCount;i ++) {
numbers[i] = Integer.parseInt(numberStr[i]);
}
System.out.println(getStickLength(numbers));
}
} finally {
if (reader != null) try {reader.close();} catch(IOException ie) {}
}
}
public static int getStickLength(int[] divStickLens) {
sortDesc(divStickLens); // 내림차순으로 막대길이들을 정렬한다.
int maxNum = divStickLens[0]; // 가장 큰 막대길이
int sum = sum(divStickLens); // 막대길이들의 총합
for (int divNum = maxNum; divNum < sum; divNum++) {
if (sum % divNum == 0) {
if (appendStick(divNum, divStickLens) == 0) {
return divNum;
}
}
}
return -1;
}
/**
* <p>내림차순으로 숫자들을 정리한다.</p>
*
* @param numbers
*/
public static void sortDesc(int[] numbers) {
if (numbers != null) {
for (int i = 0; i < numbers.length; i++) {
for (int j = i + 1; j < numbers.length; j++) {
if (numbers[i] < numbers[j]) {
int temp = numbers[i];
numbers[i] = numbers[j];
numbers[j] = temp;
}
}
}
}
}
/**
* <p>숫자들의 총 합을 구한다.</p>
*
* @param numbers 숫자들
* @return 합
*/
public static int sum(int[] numbers) {
int sum = 0;
if (numbers != null) {
for (int n : numbers) {
sum += n;
}
}
return sum;
}
/**
* <p>잘려진 막대들을 붙여서 원래 막대를 만든다.</p>
*
* @param stickLen 원래 막대의 길이
* @param lenList 잘려진 막대들의 길이들
* @return 남겨진 길이
*/
public static int appendStick(int stickLen, int[] divStickLens) {
if (stickLen < 1) {
throw new IllegalArgumentException("막대의 길이는 0보다 커야합니다.");
}
if (divStickLens == null || divStickLens.length == 0) {
throw new IllegalArgumentException("나눠진 막대의 길이 정보가 존재하지 않습니다.");
}
List<Integer> stickList = new ArrayList<Integer>();
for (int n : divStickLens) {
stickList.add(n);
}
int remain = 0;
while (remain == 0 && stickList.size() > 0) {
remain = stickLen;
for (int beingIndex = 0; beingIndex < stickList.size() && remain > 0; beingIndex++) {
int index = beingIndex;
List<Integer> remainList = new ArrayList<Integer>(stickList);
while (remain > 0 && index < remainList.size()) {
if (remain - remainList.get(index) >= 0) {
remain = remain - remainList.remove(index);
} else {
index++;
}
}
if (remain == 0) {
stickList = remainList;
} else {
remain = stickLen;
}
}
}
return remain;
}
}
Q7. 문장 비교
- 초점은 어디에 두느냐에 따라 풀이과정이 틀려지는 문제인데, 본인은 문자 비교보다는 단어 비교에 중점을 두었다.
- 구분자를 공백(" ")과 마침표(.)로 단어를 추출한 후 비교하였는데, 현재 구현상에서는 구분자도 단어로 인식(?)하는 문제점이 있어서 수정을 해야하지만, 귀찮아서 패스~. ^^;
- 처음는 대용량(?) 처리를 위해 토큰을 나누는 부분을 별도의 클래스로 분리해서 만들려고 했으니, 게으름병이도져서, 메모리상에서 그냥 나눠버림. ^^;
package synap;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintStream;
import java.util.ArrayList;
import java.util.List;
public class Answer7 {
private static char[] delimiters = {' ', '.'};
public static void main(String[] args) throws Exception {
String filename = "q7_input.txt";
BufferedReader reader = null;
try {
reader = new BufferedReader(new InputStreamReader(Answer7.class.getResourceAsStream(filename)));
String text1 = reader.readLine();
String text2 = reader.readLine();
printDiffence(text1, text2, System.out);
} finally {
if (reader != null) try {reader.close();} catch(IOException ie) {}
}
}
/**
* <p>두 문장의 차이점을 출력한다.</p>
* @param text1
* @param text2
*/
private static void printDiffence(String text1, String text2, PrintStream out) {
List<String> text1TokenList = getTokenList(text1);
List<String> text2TokenList = getTokenList(text2);
int text1TokenIndex = 0;
int text2TokenIndex = 0;
int text1TokenIndexOffset = 0;
int text2TokenIndexOffset = 0;
while (text1TokenIndex < text1TokenList.size()) {
String text1Token = text1TokenList.get(text1TokenIndex);
text2TokenIndexOffset = getTokenIndex(text2TokenList, text1Token, text2TokenIndex + text2TokenIndexOffset) - text2TokenIndex;
if (text1TokenIndexOffset == text2TokenIndexOffset) {
text1TokenIndex++;
text2TokenIndex++;
} else {
int text2TokenIndexOffsetByText1Token = text2TokenIndexOffset;
String text2Token = text2TokenList.get(text2TokenIndex);
int text1TokenIndexOffsetByText2Token = getTokenIndex(text1TokenList, text2Token, text1TokenIndex + text1TokenIndexOffset) - text1TokenIndex;
if (text1TokenIndexOffsetByText2Token < 0 && text2TokenIndexOffsetByText1Token < 0) {
// 둘 다 없을 경우 변경된것임.
int pos = 0;
for (int i = 0; i < text1TokenIndex; i++) {
String token = text1TokenList.get(i);
pos+= token.length();
}
out.println("pos " + pos + " changed " + text1Token.length() + " chars from \"" + text1Token + "\" to \"" + text2Token + "\"");
text1TokenIndex++;
text2TokenIndex++;
} else if (text1TokenIndexOffsetByText2Token < 0) {
// text1에 없을 경우 추가된것임
int pos = 0;
for (int i = 0; i < text1TokenIndex; i++) {
String token = text1TokenList.get(i);
pos+= token.length();
}
StringBuilder tokensSB = new StringBuilder();
for (int i = text2TokenIndex; i < text2TokenIndex + text2TokenIndexOffsetByText1Token; i++) {
String token = text2TokenList.get(i);
tokensSB.append(token);
}
out.println("pos " + pos + " inserted " + tokensSB.length() + " chars \"" + tokensSB.toString() + "\"");
text2TokenIndex = text2TokenIndex + text2TokenIndexOffsetByText1Token;
} else {
// text2에 없을 경우 삭제된검임
StringBuilder tokensSB = new StringBuilder();
int pos = 0;
for (int i = 0; i < text1TokenIndex + text1TokenIndexOffsetByText2Token; i++) {
String token = text1TokenList.get(i);
pos+= token.length();
if (i >= text1TokenIndex) {
tokensSB.append(token);
}
}
pos = pos - tokensSB.length();
out.println("pos " + pos + " deleted " + tokensSB.length() + " chars \"" + tokensSB.toString() + "\"");
text1TokenIndex = text1TokenIndex + text1TokenIndexOffsetByText2Token;
}
}
text1TokenIndexOffset = 0;
text2TokenIndexOffset = 0;
}
}
/**
* <p>해당 토큰의 위치를 반환한다.</p>
*
* @param tokenList
* @param token
* @param beingIndex
* @return
*/
public static int getTokenIndex(List<String> tokenList, String token, int beingIndex) {
for (int i = beingIndex; i < tokenList.size(); i++) {
// 대소문자 무시
if (tokenList.get(i).equalsIgnoreCase(token)) {
return i;
}
}
return -1;
}
/**
* <p>문자열을 구분자로 나눈다.</p>
* @param text
* @return
*/
public static List<String> getTokenList(String text) {
List<String> tokenList = new ArrayList<String>();
int textLen = text.length();
int index = 0;
int beginIndex = 0;
int endIndex = 0;
for (index = 0; index < textLen; index++) {
if (isDelimiter(text.charAt(index))) {
endIndex = index;
String token = text.substring(beginIndex, endIndex);
if (token.length() > 0) {
tokenList.add(token);
}
beginIndex = endIndex;
endIndex = endIndex + 1;
token = text.substring(beginIndex, endIndex);
tokenList.add(token);
beginIndex = endIndex;
}
}
return tokenList;
}
/**
* <p>해당 문자가 구분자인지 판단한다.</p>
*
* @param c
* @return
*/
public static boolean isDelimiter(char c) {
for (char d : delimiters) {
if (d == c) {
return true;
}
}
return false;
}
/**
* <p>해당 문자열이 구분자인지 판단한다.</p>
*
* @param str
* @return
*/
public static boolean isDelimiter(String str) {
if (str == null) {
return false;
}
if (str.length() == 1) {
return isDelimiter(str.charAt(0));
} else {
return false;
}
}
}
- 넋두리
: 개발자라면 당연히 논리적인 사고능력으로 문제를 해결해야하는데, 불행히도 본인은 그렇게 하지 못한다. 본인은 엉성한 직관력과 실험(?)&관찰(?)로 문제를 해결(쉽게 말해서 찍는다. ^^;)하는데, 아직까지 큰 사고(?)없이 지내온게 신기할따름이다. ^^; 위의 문제들도 대부분 찍어서(?) 푼것들인데, 틀렸다면 어쩔수 없고, 맞았다면 잘 찍은것일뿐이다. ^^; 본인에게 필요한건, 일어날 수 있는 모든수의 테스트 데이터뿐~~~~ ^^;;;;;
: 이자리를 빌어서 재미있는 문제를 던져~주신 사이냅소프트에게 감사의 인사를 ^^
Q6. 막대 자르기 코드에 문제가 있었다. 막대기 합체 로직이 잘못되어서 제대로 계산을 못하는 문제인데, 땜빵으로 수정을 해놨지만, 이것도 정상적으로 작동하리라는 보장이 없으니... 쿨럭... ^^;
기존에는 큰수부터 더해나가서 해당 막대기의 길이에 부합하는지 판단했는데, "큰수" + "큰수 다음의 수" 이렇게 계산이 일어나서, "큰수 다음의 수"가 목적에 부합하지 않을 경우 그 다음의 수부터 계산하는 로직이 빠져있어서, 특정 숫자에서 꽥하는 성질을 발견하여서 수정한것이다. 사실 수정한 코드도 자신이 없는관계로... 누가 한번 정리해주셨으면 감사~감사~ ^^;
- 기존 코드
int remain = 0;
while (remain == 0 && remainList.size() > 0) {
remain = stickLen;
int index = 0;
while (remain > 0 && index < remainList.size()) {
if (remain - remainList.get(index) >= 0) {
remain = remain - remainList.remove(index);
} else {
index++;
}
}
}
- 변경 후 코드
int remain = 0;
while (remain == 0 && stickList.size() > 0) {
remain = stickLen;
for (int beingIndex = 0; beingIndex < stickList.size() && remain > 0; beingIndex++) {
int index = beingIndex;
List<Integer> remainList = new ArrayList<Integer>(stickList);
while (remain > 0 && index < remainList.size()) {
if (remain - remainList.get(index) >= 0) {
remain = remain - remainList.remove(index);
} else {
index++;
}
}
if (remain == 0) {
stickList = remainList;
} else {
remain = stickLen;
}
}
}
옆에분(?)이 푼거랑 비교를 해보니, 전체적인 개념(?)은 비슷한거 같고 눈에 띄는 한가지. 본인은 끝점을 무식하게 더했는데, 한줄로 표현해주시는 센스~~
protected static int getEndPoint(int level) {
int k = 0;
int n = 0;
for (int i = 0; i < level; i++) {
k = k + 1;
n = n + k;
}
return n;
}
이랬던 놈이~ protected static int getEndPoint(int level) {
return level * (level - 1) / 2 + level;
}
이렇게 다이어트~~ 역시 사람은 배워야하나 ^^;;
퀴즈.doc