level 1. 나누어 떨어지는 숫자 배열 (java)

|

문제출처


문제

divisible 메소드는 int형 배열 array와 int divisor를 매개변수로 받습니다. array의 각 element 중 divisor로 나누어 떨어지는 값만 포함하는 새로운 배열을 만들어서 반환하도록 divisible에 코드를 작성해 보세요.

예를들어 array가 {5, 9, 7, 10}이고 divisor가 5이면 {5, 10}을 리턴해야 합니다.

풀이코드

  • ArrayList 에 조건에 맞는 값을 추가하고, 이를 다시 Array 로 변경하여 리턴하였다.
  • ArrayList 는 .toArray() 를 통해서 int[] 배열로 쉽게 변경되지 않는다. (Integer, int 의 차이 때문에)
  • 따라서 ArrayList 내부의 모든 element 를 int로 형변환 해야한다.
    이때 stream의 mapToInt 메소드를 활용하면 간단하게 처리 가능하다.
import java.util.Arrays;
import java.util.ArrayList;

class Divisible {
    public int[] divisible(int[] array, int divisor) {
      ArrayList<Integer> divArray = new ArrayList<Integer>();
      for(int i : array){
          if(i % divisor == 0){
          divArray.add(i);
        }
      }

      int[] ret = new int[divArray.size()];
      for(int i=0; i<ret.length; i++){
        ret[i] = divArray.get(i).intValue();      
      }

      return ret;
    }

    // 아래는 테스트로 출력해 보기 위한 코드입니다.
    public static void main(String[] args) {
      Divisible div = new Divisible();
      int[] array = {5, 9, 7, 10};
      System.out.println( Arrays.toString( div.divisible(array, 5) ));
    }
}

다른사람 코드

import java.util.ArrayList;
import java.util.Arrays;

public class Divisible {
    public int[] divisible(int[] array, int divisor) {
      ArrayList<Integer> ret = new ArrayList<>();
      for (int i = 0; i < array.length; i++) {
          if (array[i] % divisor == 0) {
              ret.add(array[i]);
          }
      }

      return ret.stream().mapToInt(i -> i).toArray();
    }

    // 아래는 테스트로 출력해 보기 위한 코드입니다.
    public static void main(String[] args) {
        Divisible div = new Divisible();
        int[] array = { 5, 9, 7, 10 };
        System.out.println(Arrays.toString(div.divisible(array, 5)));
    }
}
import java.util.Arrays;

class Divisible {
    public int[] divisible(int[] array, int divisor) {
        //ret에 array에 포함된 정수중, divisor로 나누어 떨어지는 숫자를 순서대로 넣으세요.
        return Arrays.stream(array).filter(factor -> factor % divisor == 0).toArray();
    }
    // 아래는 테스트로 출력해 보기 위한 코드입니다.
    public static void main(String[] args) {
        Divisible div = new Divisible();
        int[] array = {5, 9, 7, 10};
        System.out.println( Arrays.toString( div.divisible(array, 5) ));
    }
}

배운점

  • ArrayList 는 .add() 메소드를 통해서 요소를 추가할 수 있지만, Array는 array[0] 과 같이 index를 사용해야 한다.
  • Arrays.toString() 를 통해서 배열을 그대로 print 할 수 있다. (Returns a string representation of the contents of the specified array.)
  • .stream() 을 통해서 collections 를 좀 더 편리하게 처리할 수 있다. (API 문서, 참고 글)

level 1. 가운데 글자 가져오기 (java)

|

문제출처


문제

getMiddle메소드는 하나의 단어를 입력 받습니다.
단어를 입력 받아서 가운데 글자를 반환하도록 getMiddle메소드를 만들어 보세요. 단어의 길이가 짝수일경우 가운데 두글자를 반환하면 됩니다.
예를들어 입력받은 단어가 power이라면 w를 반환하면 되고, 입력받은 단어가 test라면 es를 반환하면 됩니다.

풀이코드

  • 인자로 주어진 stirng의 길이를 구하여, .length()
  • 홀수인 경우 문자열.charAt(위치)를 활용하여 가운데 글자를 char 자료형으로 가져온다.
    • 이 경우 함수의 리턴 자료형이 String 이기 때문에 오류가 발생한다.
    • char -> String 으로 변환하는 가장 효율적인 방법은 Character.toString(대상) 이다.
  • 짝수인 경우 문자열.substring(시작, 끝)으로 가운데 글자들을 String 자료형으로 가져올 수 있다.
class StringExercise{
    String getMiddle(String word){
    int len = word.length();
    if (len % 2 == 1){
      // return word.charAt(len/2)+"";
      // char > Stirng 형변환
      // Least efficient and most memory-inefficient, but common amongst beginners because of its simplicity
      return Character.toString(word.charAt(len/2)); //  Most efficient way
    }else{
      return word.substring(len/2-1, len/2+1);        
    }
  }
  // 아래는 테스트로 출력해 보기 위한 코드입니다.
  public static void  main(String[] args){
    StringExercise se = new StringExercise();
    System.out.println(se.getMiddle("power"));
  }
}

다른사람 코드

  • .substring() 메소드를 활용하면 Stirng 으로 리턴값을 받을 수 있다.
  • 3항 연산자를 활용한다.
class StringExercise{
    String getMiddle(String word){
      int length = word.length();
      int index = length / 2;
      return (length%2==0) ? word.substring(index-1, index+1) : word.substring(index, index+1);
    }
    // 아래는 테스트로 출력해 보기 위한 코드입니다.
    public static void  main(String[] args){
      StringExercise se = new StringExercise();
      System.out.println(se.getMiddle("power"));
  }
}

Self Number (python)

|

문제

어떤 자연수 n이 있을 때, d(n)을 n의 각 자릿수 숫자들과 n 자신을 더한 숫자라고 정의하자.
예를 들어
d(91) = 9 + 1 + 91 = 101
이 때, n을 d(n)의 제네레이터(generator)라고 한다. 위의 예에서 91은 101의 제네레이터이다.
어떤 숫자들은 하나 이상의 제네레이터를 가지고 있는데, 101의 제네레이터는 91 뿐 아니라 100도 있다.
그런데 반대로, 제네레이터가 없는 숫자들도 있으며, 이런 숫자를 인도의 수학자 Kaprekar가 셀프 넘버(self-number)라 이름 붙였다.
예를 들어 1, 3, 5, 7, 9, 20, 31 은 셀프 넘버 들이다.
1 이상이고 5000 보다 작은 모든 셀프 넘버들의 합을 구하라.

풀이코드

def self_number():
    li = []
    for i in range(1,5001):
        li.append(i + sum([int(j) for j in str(i)]))

    return sum(set(range(1,5001)) - set(li))

다른사람 코드

sum(set(range(1, 5000)) - {x + sum([int(a) for a in str(x)]) for x in range(1, 5000)})

level 1. 최대값과 최소값 (Java, Python)

|

문제출처

Java 공부를 시작하고 처음 풀어본 간단한 알고리즘 문제이다.
문자열을 배열로 만드려면 어떻게 하지? 오름차순 정렬은 어떻게 하지?
아직 모르는 것이 많지만 이렇게 하나씩 찾아가면서 익히는게 재미있기도 하고 기억에도 잘 남는 것 같다.

파이썬을 처음 공부하고 알고리즘 문제를 풀기 시작했을 때가 생각난다.
리스트 원소의 합을 구하는 sum() 함수를 찾아보고 메모해둔 글을 다시 읽었는데,
이렇게 간단한걸 모르던 때도 있었구나 싶었다. (옛날 같은데 그게 겨우 3개월 전이라니!)

그래도 다행인건 간단한 문제라면 어떻게 접근해서 해결해야겠다는 그림이 그려진다는 것이다.
그다음에 해야 하는건 원하는 걸 구현하려면 Java의 무슨 메소드, 패키지를 사용해야 하는지 찾아보는 것
그리고 codility 덕분에 시간복잡도에 대한 고민을 한번 더 할 수 있게 된 것 같다.

처음이라 약간 막막한 느낌이 들기는 하지만
이것도 금방 지나가겠지!

문제

getMinMaxString 메소드는 String형 변수 str을 매개변수로 입력받습니다. str에는 공백으로 구분된 숫자들이 저장되어 있습니다. str에 나타나는 숫자 중 최소값과 최대값을 찾아 이를 “(최소값) (최대값)”형태의 String을 반환하는 메소드를 완성하세요. 예를들어 str이 “1 2 3 4”라면 “1 4”를 리턴하고, “-1 -2 -3 -4”라면 “-4 -1”을 리턴하면 됩니다.

풀이코드

Java

접근

  • 문자열을 배열로 변경한다. (.split() 메소드 활용)
  • 배열의 각 요소를 정수로 변경하여 새로운 배열(arrayInt)에 담는다. (Integer.parseInt() 활용)
  • 배열을 오름차순으로 정렬한다. (Arrays.sort() 활용)
  • 맨 처음 요소(최소값) 맨 마지막 요소(최대값)을 문자열로 리턴한다.

고민

  • sorting 을 하려면 최소 O(N LogN)의 시간복잡도가 발생한다.
  • 차라리 배열을 순회하면서 최대값, 최소값을 찾는게 효율적일 것 같다.
import java.util.Arrays;

public class GetMinMaxString2 {
	public String getMinMaxString(String str) {
		String[] array = str.split(" ");
		int[] arrayInt = new int[array.length];

		for (int i = 0; i < arrayInt.length; i++) {
			arrayInt[i] = Integer.parseInt(array[i]); // 배열의 각 요소를 정수로 변경
		}

		Arrays.sort(arrayInt); // 최소 O(N LogN)의 시간복잡도
		String result = arrayInt[0] + " " + arrayInt[arrayInt.length - 1];

		return result;

	}

	public static void main(String[] args) {
		String str = "1 2 3 4";
		GetMinMaxString2 minMax = new GetMinMaxString2();
		System.out.println("최소값과 최대값은?" + minMax.getMinMaxString(str));
	}
}

Python

  • min, max 함수를 사용해서 간단하게 구현 가능하다.
def solution(str):
    li = str.split(' ')
    return print("최소값과 최대값은", min(li), max(li))

다른사람 풀이

public class GetMinMaxString {
	public String getMinMaxString(String str) {
		String[] tmp = str.split(" ");
		int min, max, n;
		min = max = Integer.parseInt(tmp[0]);
		for (int i = 1; i < tmp.length; i++){
			n = Integer.parseInt(tmp[i]);
			if (min > n) min = n;
			if (max < n) max = n;
		}

		return min + " " + max;

	}

	public static void main(String[] args) {
		String str = "1 2 3 4";
		GetMinMaxString minMax = new GetMinMaxString();
		System.out.println("최대값과 최소값은?" + minMax.getMinMaxString(str));
	}

}

codility 4-1. FrogRiverOne

|

문제출처

예전에 2시간을 고민하고도 풀지 못했던 문제였다.
한달이 지나고 나서 다시 풀어보았는데, 시간복잡도 O(N^2)로 풀었다가 시간복잡도 O(N)으로 성능 개선하는데 성공했다. 너무 뿌듯하다!! :)


문제

A small frog wants to get to the other side of a river. The frog is initially located on one bank of the river (position 0) and wants to get to the opposite bank (position X+1). Leaves fall from a tree onto the surface of the river.

You are given a zero-indexed array A consisting of N integers representing the falling leaves. A[K] represents the position where one leaf falls at time K, measured in seconds.

The goal is to find the earliest time when the frog can jump to the other side of the river. The frog can cross only when leaves appear at every position across the river from 1 to X (that is, we want to find the earliest moment when all the positions from 1 to X are covered by leaves). You may assume that the speed of the current in the river is negligibly small, i.e. the leaves do not change their positions once they fall in the river.

For example, you are given integer X = 5 and array A such that:

  A[0] = 1
  A[1] = 3
  A[2] = 1
  A[3] = 4
  A[4] = 2
  A[5] = 3
  A[6] = 5
  A[7] = 4
In second 6, a leaf falls into position 5. This is the earliest time when leaves appear in every position across the river.

Write a function:

def solution(X, A)
that, given a non-empty zero-indexed array A consisting of N integers and integer X, returns the earliest time when the frog can jump to the other side of the river.

If the frog is never able to jump to the other side of the river, the function should return −1.

For example, given X = 5 and array A such that:

  A[0] = 1
  A[1] = 3
  A[2] = 1
  A[3] = 4
  A[4] = 2
  A[5] = 3
  A[6] = 5
  A[7] = 4
the function should return 6, as explained above.

Assume that:

N and X are integers within the range [1..100,000];
each element of array A is an integer within the range [1..X].
Complexity:

expected worst-case time complexity is O(N);
expected worst-case space complexity is O(X), beyond input storage (not counting the storage required for input arguments).

풀이코드

첫번째 시도

  • 시간복잡도 : O(N ** 2)
  • for loop 안에서 A in B 검색을 사용해서 O(N**2) 시간복잡도
def solution(X, A):
    check = [False] * X
    for idx, val in enumerate(A):
        check[val-1] = True
        if not False in check:
            return idx
    return -1   

두번째 시도

  • 시간복잡도 : O(N)
  • A in B 검색을 사용하지 않기 위해서 별도의 check_sum 변수를 활용
def solution(X, A):
    check = [0] * X
    check_sum = 0
    for i in range(len(A)):
        if check[A[i]-1] == 0:
            check[A[i]-1] = 1
            check_sum += 1
            if check_sum == X:
                return i
    return -1