2019년 4월 30일 화요일

Hackerrank Day 20 Sorting







알고리즘 연습 사이트


Day 20:Sorting



 20일차는 Bubble sort에 대해 간략히 배웠다. 

 정렬되는 모습이 마치 거품처럼 위로 이동하는 것 처럼 보이기 때문에 Bubble이라는 말이 붙었다. 
 버블 정렬은 실제 현실세상에서 써먹기에는 그리 효율이 좋지 않기 때문에 학습 용도로만 배운다.

 버블정렬은 간단히 말하면 정렬을 할 때 인접한 두개의 값을 서로 비교하여 큰 값이 작은 값보다 앞에 있다면 두 값의 위치를 서로 바꾸는 것이다.


키 포인트는 최초 1회 비교에서 가장 큰 값은 마지막에 위치하게 된다.


 배열의 시작 지점부터 바로 인접한 변수를 계속 비교하여, swap하거나 그대로 두면서 배열의 끝까지 계속 비교해야 한다.
 그리고 2 싸이클에서 다시 배열의 처음으로 되돌아와서 다시 순서대로 비교한다. 

 규칙을 찾아내보면 배열의 길이에서 1을 뺀 만큼 도는 바깥 반복문 1개와, 그 내부에 인접한 두개의 변수를 비교하면서 배열의 위치를 계속 이동시키는 반복문이 필요하다. 


버블소트 기본 동작을 이해하고 나서 코드를 보면 이해가 쉽다.

오늘 문제는 버블소트를 구현하고 몇 번 swap이 일어났는지와 첫번째와 마지막 요소를 출력하는 것이다.

첫번째 버전은 마지막으로 스왑이 일어난 지점을 endPosition에 저장하고 endPosition만큼만 반복을 한다. 

이렇게 되면 어차피 마지막 값이 최대값이 들어있는 부분은 검사를 안하게 되는 이점이 있다.
그리고 endPosition이 0이 되면 while 반복문을 탈출하게 된다. 


(1) 첫번째 버블소트


public static void bubbleSort(int[] x) {
    printArray("Initial", x);

    int endPosition = x.length - 1;
    int swapPosition;

    while( endPosition > 0 ) {
        swapPosition = 0;

        for(int i = 0; i < endPosition; i++) {

            if( x[i] > x[i + 1] ){
                // Swap elements 'i' and 'i + 1':
                int tmp = x[i];
                x[i] = x[i + 1];
                x[i + 1] = tmp;

                swapPosition = i;
            } // end if

        } // end for

        endPosition = swapPosition;
    } // end while
} // end bubbleSort


(2) 두번째 버블소트


public class Solution {

    public static void main(String[] args) {
        Scanner in = new Scanner(System.in);
        int n = in.nextInt();
        int[] a = new int[n];
        for(int a_i=0; a_i < n; a_i++){
            a[a_i] = in.nextInt();
        }
        
        int numSwaps = 0; //Swap이 일어난 total 횟수
        int firstElement = 0; //첫번째 배열 데이터 저장
        int lastElement =0; //마지막 배열 데이터 저장
        int tmp = 0; 
        for(int i =0 ; i < a.length ; i++){ 
            for(int j = 0 ; j < a.length -1 ; j++){
                if(a[j] > a[j+1]){
                   tmp = a[j+1];
                   a[j+1] = a[j];
                   a[j] = tmp;
                   numSwaps++; 
                }
            }
        }
        System.out.println("Array is sorted in "+numSwaps+" swaps.");
        System.out.println("First Element: "+a[0]);
        System.out.println("Last Element: "+a[a.length-1]);
    }
}

두번째는 모든 루프에서 배열 전체를 다 검사하는 단순한 버블소트이다.



2019년 4월 29일 월요일

Hackerrank Day 19 Interfaces







알고리즘 연습 사이트


Day 19:Interfaces



 인터페이스는 추상클래스와 비슷하지만 좀 더 규칙을 강화한 문법이다. 
 인터페이스는 new를 이용하여 객체를 생성할 수 없다. 
 왜냐하면 인터페이스에는 몸체가 없는 메소드들 밖에 없기 때문이다.

인터페이스를 implement 하는 클래스들은 인터페이스의 메소드들을 무조건 구현해야 한다. 
 인터페이스를 implements해놓고 구현을 하지 않으면 컴파일 에러가 뜬다.

 인터페이스의 장점은 간단하게 말하면 이미 인터페이스를 구현한 클래스들이나 앞으로 구현될 클래스들의 기능이 예측이 가능하다는 것이다. 
 클래스를 직접 뜯어보지 않아도 기능을 예측 할 수 있다는 것은 실제 개발에서 매우 유용한 장점이다. 

 아래 문제는 어떤 자연수의 약수들의 합을 구현한 코드다.
AdvancedArithmetic 인터페이스를 구현한 것이 Calculator 클래스가 되고, Calculator 클래스에서는 반드시 divisorSum 메소드의 몸체를 구현해야만 한다. 



interface AdvancedArithmetic{
   int divisorSum(int n);
}
class Calculator implements AdvancedArithmetic {
    public int divisorSum(int n) {
        //약수들의 합 구하기
        int sum = 0;
        int i = 1 ;
        while(n >= i){
            if(n % i == 0){ //나누어 떨어지면
                sum += i ;
            }
            i++;     
        }
        return sum;
    }
}

i가 1부터 n이 될때까지 n을 나누면서 나머지가 0이면 나누어 떨어지므로 sum에 i의 값을 누적하고 sum을 리턴한다.


2019년 4월 23일 화요일

Hackerrank Day 18 Queues and Stacks







알고리즘 연습 사이트


Day 18:Queues and Stacks



 자료구조의 가장 기본이 되는 Queue와 Stack이다. 

*참고
Stack: https://docs.oracle.com/javase/7/docs/api/java/util/Stack.html
Queue: https://docs.oracle.com/javase/7/docs/api/java/util/Queue.html

* Stack 
Last In First Out (LIFO).
가장 나중에 넣은 것이 처음에 나오는 형태. 
밑이 막혀 있는 그릇에 데이터를 차곡차곡 쌓고 꺼낼때는 가장 위부터 꺼낸다.

Stack 클래스에는 주요 메소드 3가지가 있다
-Push : Stack의 가장 맨위에 데이터를 추가한다.
-Peek : 가장 맨위의 데이터를 리턴하지만 데이터를 지우지 않는다.
-Pop : 가장 맨위의 데이터를 리턴하고 그 데이터를 지운다.

* Queue
First In First Out (FIFO)
처음에 넣은 것이 처음에 나오는 형태.
- Enqueue : 큐의 가장 마지막의 그 다음에 데이터를 넣는다.
- Dequeue : 큐의 가장 앞부분(head)의 데이터를 리턴하고 그 값을 큐에서 삭제한다. 그러고 나면 두 번째에 있던 데이터가 head가 된다. 




오늘 문제는 앞으로 읽으나 거꾸로 읽으나 동일한 단어나 문장이 되는 문자열을 찾아내는 것이다. 그러한 문장 혹은 구를 palindrome이라고 한다.

문자열을 char형으로 쪼개어 Stack과 Queue에 각각 넣고 Stack에서는 pop을 하여 리턴되는 문자와, Queue의 remove메소드를 호출하여 리턴되는 결과를 서로 비교하여 문자열의 절반까지 비교를 하여 값이 완벽히 동일하다면 palindrome, 다르다면 palindrome이 아닌 것이다.

여기서 중요한 것은 스택과 큐의 성질을 이해하고 클래스의 메소드의 사용법을 이해하면 된다.

위에 링크해 둔 API 문서에 상세히 나와 있다.



public class Solution {
    // Write your code here.
    Stack stack = new Stack();
    Queue queue = new LinkedList();

    void pushCharacter(char ch){
        stack.push(ch);
    }
    void enqueueCharacter(char ch){
        queue.add(ch);
    }
    char popCharacter(){
        return stack.pop();
    }
    char dequeueCharacter(){
        return queue.remove();
    }
 
    public static void main(String[] args) {
        Scanner scan = new Scanner(System.in);
        String input = scan.nextLine();
        scan.close();

        // Convert input String to an array of characters:
        char[] s = input.toCharArray();

        // Create a Solution object:
        Solution p = new Solution();

        // Enqueue/Push all chars to their respective data structures:
        for (char c : s) {
            p.pushCharacter(c);
            p.enqueueCharacter(c);
        }

        // Pop/Dequeue the chars at the head of both data structures and compare them:
        boolean isPalindrome = true;
        for (int i = 0; i < s.length/2; i++) {
            if (p.popCharacter() != p.dequeueCharacter()) {
                isPalindrome = false;                
                break;
            }
        }

        //Finally, print whether string s is palindrome or not.
        System.out.println( "The word, " + input + ", is " 
                           + ( (!isPalindrome) ? "not a palindrome." : "a palindrome." ) );
    }
}

2019년 4월 19일 금요일

Hackerrank Day 17 More Exceptions







알고리즘 연습 사이트


Day 17:More Exceptions



 전날에 이어서 예외 처리 문제를 풀어보자. 
어떤 메소드에 예외를 던지겠다는 표시를 한 후, 메소드 안에서 throw 키워드를 이용하여 고의로 발생시킬 수 있다. 
그러면 메소드를 호출한 곳으로 예외는 전달된다. 
예외는 이런 식으로 계속 상위로 퍼져 나가는데 결국 최상위에서 예외는 반드시 잡아내어서(try~catch) 처리되어야 한다. 

아래 코드는 Calculator 클래스 안에 거듭제곱(n^p)을 구하는 power 메소드에서 중 N or P가 음수일 때 예외를 던지는 코드이다. 


class Calculator{
    int power(int n, int p) throws Exception{
        int result = 1;
        if(n<0 || p<0){
            throw new Exception("n and p should be non-negative");
        }else{
            for(int i = 0 ; i < p ; i ++){
                result *= n;
            }
        }
        return result;
    }
}
class Solution{

    public static void main(String[] args) {
    
        Scanner in = new Scanner(System.in);
        int t = in.nextInt();
        while (t-- > 0) {
        
            int n = in.nextInt();
            int p = in.nextInt();
            Calculator myCalculator = new Calculator();
            try {
                int ans = myCalculator.power(n, p);
                System.out.println(ans);
            }
            catch (Exception e) {
                System.out.println(e.getMessage());
            }
        }
        in.close();
    }
}

power 메소드를 호출한 상위부분으로 예외가 던져지고, 그 부분이 try 문으로 감싸지면서 예외를 catch한다.

2019년 4월 18일 목요일

Hackerrank Day 16 Exceptions - String to Integer







알고리즘 연습 사이트


Day 16:Exceptions - String to Integer



 코드를 작성하다 보면 예기치 못한 버그나 에러가 발생 할 수 있고 프로그램 동작이 멈출 수 있다.
 그런 상황에서 자바와 같은 언어는 예외처리 기능을 제공한다.

* try catch finally
 오류가 발생 할 수 있는 부분들을 try로 감싸고 catch로 에러를 잡는다.
 finally 안에는 try로 감싼 지점을 벗어나서도 반드시 실행되야 하는 코드들을 작성한다. 
finally로 감싸진 부분은 에러가 발생하더라도 무조건 실행되야 하는 코드를 작성한다.

* try with resources (1.7)
 java.lang.AutoCloseable 이나 java.lang.Closeable 클래스들을 구현하는 클래스들의 exception 처리 시 자원을 자동으로 close 해주는 유용한 문법이다. 
AuthCloseable과 Closeable 클래스를 구현하는 대표적인 클래스들은 Scanner, BufferedReader 등과 같은 IO 클래스들이다.


try(Scanner scan = new Scanner();){
      // 잠재적으로 예외가 발생할 가능성이 있는 코드를 작성 
} //괄호를 벗어나면 자원을 자동 해제

Closeable이나 AutoCloseable만 구현하는 클래스이기만 하면 예외 처리나 try 구문을 벗어날 때 자동으로 close() 가 호출된다.

오늘 문제는 String을 Integer로 변환하면서 숫자는 출력하고 문자열을 변환하려고 할 때는 try catch 구문을 이용해 에러 메시지를 출력하도록 한다.

public class Solution {
    public static void main(String[] args) {
        Scanner in = new Scanner(System.in);
        String S = in.next();
        try{
            int n = Integer.parseInt(S);
            System.out.println(n);

        }catch(Exception e){
            System.out.println("Bad String");
        }
    }
}



2019년 4월 17일 수요일

Hackerrank Day 15 Linked List







알고리즘 연습 사이트


Day 15:Linked List


List reference: https://docs.oracle.com/javase/tutorial/collections/interfaces/list.html

Linked List 연결된 리스트, 리스트의 요소 한개가 다음 요소(노드)와 연결되어 있다는 의미이다. 
자세한 내용은 위의 java API docs 참조 문헌에 있다.
링크드 리스트에서 노드들은 다음번 차례의 노드의 참조 주소를 가지고 있어서 아래의 그림과 같이 연결이 되는 형태이다. 
마지막 tail 노드는 다음 요소가 없기 때문에 null를 가르키는 특징을 가진다.
myLinkedList.png
LinkedList

정의된 Node 클래스를 이용하여 LinkedList의 insert 메소드를 구현해보는 것이 Day 15의 문제이다.

KeyPoint는 첫번째 Head Node의 객체의 참조 주소를 절대로 잃어버려서는 안된다는 점이다.

새로 생기는 노드로 참조를 이동해서 연결해야 한다(?)는 강박관념에 사로잡혀 굉장히 어렵게 문제를 풀었다.
지금 구현하고자 하는 insert 메소드는 최초의 노드를 계속 return 해주어야 하는게 핵심이다. 
왜냐하면 첫번째 노드를 잃어버리게 되면, LinkedList 객체의 참조 주소 자체를 잃어버리는 것과 같다.
시작 노드자체가 Null인 경우/중간 노드/꼬리 노드의 특징을 이용하여 if 분기 처리를 한다.  
중간 노드인 경우 next 값이 존재 하므로 next가 null인 경우까지 반복하면서 꼬리를 찾다가 꼬리노드의 next에 새로운 노드를 만들어 값을 넣으면 된다.



노드 클래스는 아래와 같이 next 라는 다음 노드의 주소를 저장하는 참조변수와, data를 저장하는 int형 변수로 이루어져 있다.
class Node {
   int data;
   Node next;
   Node(int d) {
       data = d;
       next = null;
   }
}


방법은 해커스랭크의 도움을 받아 2가지로 정리해보았다.
1번 방법이 코드상으로 더 깔끔해 보인다. 
소스 코드를 보면 메소드 인자로 전달되는 head 변수가 다른 노드 주소로 변동되는 지점이 전혀 없다.




//1번 방법
public static Node insert(Node head,int data) {
    if(head == null){ //처음 시작 지점. head 가 null로 들어온 경우.
        return new Node(data);
    }else if(head.next == null){ //꼬리노드라면,
        Node newNode = new Node(data); //새로운 노드를 만들면서 data를 생성자를 통해 초기화
        head.next = newNode; // 현재 노드의 next 변수에 새로 만든 노드의 참조주소를 세팅한다.
    }else{ //중간 노드라면,
        insert(head.next , data); //재귀 호출을 통해 자신의 꼬리를 찾는다.
    }
    return head; //계속 head 노드를 리턴해 주어 첫번째 참조 변수 값을 잃지 않는다.
}


//2번 방법
public static Node insert(Node head,int data) {    
    if(head == null){ //1번과 동일
        return new Node(data);
    }else if(head.next == null){ //1번과 동일
        Node nextNode = new Node(data);
        head.next = nextNode;
    }else{ //중간 노드라면,
        /*
          tmp 참조 변수에 head 참조 주소를 복사한다.
          head의 값을 복사하는 경우는 while문 안에서 꼬리노드를 찾기 위해 tmp값에 변동이 일어난다.
          만약 tmp 값을 복사하지 않고 head값을 그대로 이용하면 head 참조변수 값을 잃어버리게 된다. 
        */
        Node tmp = head; 
        while(tmp.next !=null){ //tmp의 next가 null이 아닐 때까지 반복한다.
            tmp = tmp.next; //tmp에 tmp.next를 대입하여 다음 노드의 next값을 계속 체크 할 수 있도록 한다.
        }
        //while문을 벗어났다면 tmp는 꼬리노드일 것이다.
        tmp.next = new Node(data);//꼬리 노드의 next에 새로운 노드를 추가한다.
    }
    return head;
}

2019년 4월 15일 월요일

Hackerrank Day 14 Scope







알고리즘 연습 사이트


Day 14:Scope



스코프라는 것은 프로그램 안에서 어떤 변수가 미치는 영역, 범위를 말한다. 
어떤 변수가 선언되면 그 지역을 벗어날 때까지 그 변수는 유효하다.
생성자의 파라미터는 보통 인스턴스 변수와 이름을 동일하게 하고 this 키워드를 이용하여 값을 초기화 해준다. 


14일차는 int 형의 양수 배열 elements에 대해 절대값이 가장 큰 숫자를 구하는 문제이다.

어떤 두 수의 뺄셈의 절대값이 가장 크려면, 가장 큰 수에서 가장 작은 수를 빼면 된다.
두 수의 거리가 가장 긴게 절대값이 크다고 이해하면 될 것이다.
배열을 sort하면 기본 오름차순 정렬이 된다.
그리고 마지막 배열의 숫자와 0번째 숫자를 빼면 된다. 
elements에 들어있는 수에는 음수가 없으므로 단순히 빼주기만 하면 된다.


 
class Difference {
   private int[] elements;
   public int maximumDifference;

    Difference(int[] elements){
        this.elements = elements;
    }

    void computeDifference(){
        Arrays.sort(elements); //오름차순 정렬
        maximumDifference = elements[elements.length-1] - elements[0];
    }
} 

Hackerrank Day 13 Abstract Classes







알고리즘 연습 사이트
www.hackerrank.com


Day 13:Abstract Classes



추상 클래스란 ?

class를 abstract 로 선언하기만 하면 추상 클래스다. 추상 클래스 그 자체로는 인스턴스를 생성할 수 없다. 
body가 없는 추상 메소드가 1개 이상 포함되어 있어서 인스턴스를 생성할 수 없기 때문이다. 
추상 클래스를 반드시 subclass가 extends를 하여 abstract 선언된 메소드들의 body를 구현하고나서야 subclass의 인스턴스 생성(new 키워드)을 할 수 있다. 
Day 12에서 배웠던 상속 개념을 확장시킨 것이 추상 클래스 이다.

13일 문제는 추상클래스 Book을 상속하는 MyBook 클래스를 구현하는 것이다.

abstract class Book {
    String title;
    String author;
    
    Book(String title, String author) {
        this.title = title;
        this.author = author;
    }
    
    abstract void display(); //추상 메소드
}
class MyBook extends Book{ //Inherits from Book
    int price;
    MyBook(String title, String author, int price){
        super(title, author);
        this.price = price;
    }
     void display(){ //추상 메소드를 구현
        System.out.println("Title: "+title);
        System.out.println("Author: "+author);
        System.out.println("Price: "+price);
    }
}




2019년 4월 10일 수요일

Hackerrank Day 12 Inheritance







알고리즘 연습 사이트
www.hackerrank.com


Day 12:Inheritance



상속의 개념에 대해 정리해본다.

아래 소스 코드의 예시에서 Person은 부모클래스(superclass) 이며 Student 는 자식클래스(subclass) 이다.
자바의 상속은 오직 '한번' 만 허용한다.
즉 subclass는 superclass를 extents 딱 한 번만 할 수 있다.

자식 클래스가 부모 클래스의 변수, 메소드들을  그대로 상속받는데, 유일하게 상속되지 않는 것이 생성자(Constructor) 이다.

생성자라는 것 자체가 자기 자신의 클래스의 인스턴스를 초기화하는 것이다. 때문에 절대로 상속되지 않는다. 

생성자를 특별히 만들지 않으면 기본적으로 자동으로 디폴트 (비어있는) 생성자가 만들어 진다.
생성자를 새로 정의하여 파라미터를 추가하여 값을 초기화하는 경우 디폴트 생성자는 생성되지 않는다.

부모클래스를 상속하는 자식클래스는 부모클래스의 생성자를 반드시 먼저 호출해야만 한다.
그 호출을 하기 위한 방법은 super();이다.
부모클래스와 자식 클래스 둘 다 아무런 생성자를 명시하지 않은 경우에도, 자식 클래스의 자동으로 만들어지는 생성자 안에는 부모의 생성자를 호출 할 수 있게 하는 super(); 가 존재한다.

subclass인 Student 클래스에서 생성자를 이용하여 인스턴스 변수들을 초기화 하는데, 생성자가 아래의 코드와 같이 정의 되어 있는 경우에는 디폴트 생성자가 생성 되지 않기 때문에 자식 클래스의 생성자 안에서 반드시 부모 클래스의 생성자를 호출해야만 한다. 

그러면 Student 클래스를 new 할 때 Studnet의 생성자가 호출되고 super로 인해 부모의 생성자까지 호출되면서 부모의 인스턴스 변수까지 초기화 된다.

Student 객체를 생성하면 Student는 Person의 속성들을 전부 상속받았기 때문에, 
Person의 속성을 지니는 Student 객체가 한 개 만들어지게 진다. 



class Person {
 protected String firstName;
 protected String lastName;
 protected int idNumber;
 
 // 부모클래스 생성자 정의. 디폴트 생성자는 없다.
 Person(String firstName, String lastName, int identification){ 
  this.firstName = firstName;
  this.lastName = lastName;
  this.idNumber = identification;
 }
 
 // Print person data
 public void printPerson(){
   System.out.println(
    "Name: " + lastName + ", " + firstName
   +  "\nID: " + idNumber);
 }
 
}

class Student extends Person{
 private int[] testScores;

    /* 
    *   자식클래스 생성자 정의
    *   super 키워드로 부모 클래스의 생성자를 호출하여 부모 클래스의 인스턴스 변수를 초기화.
    *   그리고 자신의 인스턴스 변수를 초기화 한다.
    */
    // Write your constructor here
        public Student(String firstName, String lastName, int id, int[] scores){
            super(firstName,lastName,id);
            testScores = scores;
        }
    // 계산 메소드. 
    public char calculate (){         char grade;         int arg = 0;;         for(int i = 0 ; i < testScores.length;i++){             arg += testScores[i];         }         arg = arg / testScores.length;         if(arg >= 90 && arg <= 100){             grade = 'O';         }else if(arg >= 80 && arg <= 90){             grade = 'E';         }else if(arg >= 70 && arg <= 80){             grade = 'A';         }else if(arg >= 55 && arg <= 70){             grade = 'P';         }else if(arg >= 40 && arg <= 55){             grade = 'D';         }else{             grade = 'T';         }         return grade;     } }

위 클래스를 사용할 때는 아래와 같다.

Student s = new Student(firstName, lastName, id, testScores);
s.printPerson(); //자식 클래스에서 오버라이드를 하지 않았기 때문에 부모클래스의 메소드를 호출한다.
System.out.println("Grade: " + s.calculate() );

[결과예시]
Name: Memelli, Heraldo
ID: 8135627
Grade: O

2019년 4월 9일 화요일

Hackerrank Day 11 2D Arrays







알고리즘 연습 사이트
www.hackerrank.com


Day 11:2D Arrays


이번 문제는 아래 예시의 6x6 배열이 주어지는데,

1 1 1 0 0 0 0 1 0 0 0 0 1 1 1 0 0 0 0 0 2 4 4 0 0 0 0 2 0 0 0 0 1 2 4 0

위 배열에서 3x3의 모래시계 모양을 만들 수 있는 가짓수는 16가지가 된다.

1 1 1 1 1 0 1 0 0 0 0 0 1 0 0 0 1 1 1 1 1 0 1 0 0 0 0 0 0 1 0 1 0 0 0 0 0 0 0 0 1 1 0 0 0 0 2 0 2 4 2 4 4 4 4 0 1 1 1 1 1 0 1 0 0 0 0 0 0 2 4 4 0 0 0 0 0 2 0 2 0 2 0 0 0 0 2 0 2 4 2 4 4 4 4 0 0 0 2 0 0 0 1 0 1 2 1 2 4 2 4 0

이 모래시계들의 합 중 가장 큰 값을 찾는 것이 Day 11의 문제이다.

아래 코드를 작성하다 보니 for문 중첩이 4개나 되어버렸다.
우선 가장 바깥 for문 2개는 전체 모래시계의 반복 16가지를 뜻한다.
그리고 안쪽의 for문 2개는 모래시계를 구성하는 요소 9가지를 뜻한다.

if문 안의 조건의 의미는 모래시계 요소가 아닌 것들의 인자들만 빼고 모조리 다 더하겠다는 의미이다.
arr[k+i][z+j] 라고 작성한 이유는 행과 열을 더해줘야 모래시계가 옆으로 한칸씩 이동하거나 아래로 내려가면서 위치가 이동되기 때문이다.

int[] sum = new int[16];
int number = 0;
int max = 0;
for(int i=0 ; i<4 ; i++){ // 행   
    for(int j=0 ; j < 4 ; j++ ){ //열
        for(int k=0; k<3 ; k++ ){
            for(int z=0 ; z<3 ; z++ ){
                if( !(k==1&&z==0) && !(k==1&&z==2))
                    sum[number] += arr[k+i][z+j];
            }  
        }
        if(sum[number] > max || (i ==0 && j ==0)){
            max = sum[number];
        }
        number++;
    }
}
System.out.println(max);


max값을 구하는 것은 이전 Day 10 문제에서 삽질을 좀 해서(?) 이번엔 쉽게 이해하였다.
max값을 대입하는 과정에서 (i ==0 && j ==0) 조건이 추가가 된 이유는, 이 조건을 안 넣으면 max값이 음수인 경우에 문제가 된다.

첫 모래시계의 sum 값을 반드시 max 에 대입하여 최대값이 음수일 때에도 정확하게 출력되게 해야한다.

cf ) 아래와 같이 sort를 사용해서도 max값을 출력할 수 있다.
Arrays.sort(sum); //기본 오름차순 정렬
System.out.println(sum[sum.lenght-1]);


Hackerrank Day 10 Binary Numbers







알고리즘 연습 사이트
www.hackerrank.com


Day 10:Binary Numbers


어떤 10진수를 입력받아 2진수로 변환하면서, 연속된 1이 최대 몇번 나오는가 라는 문제이다.
while문으로 몫(n)이 0보다 클때까지 돌면서 나머지가 1이면 count 수를 증가시킨다.
count가 백업된 숫자(back)보다 크거나 같을 경우 back에 count를 대입한다. 
중간에 나머지가 0인 경우 count수를 0으로 세팅하여 처음부터 다시 연속된 1을 센다.
그러다가 back에 저장된 수보다 같거나 커지게 되면 그 수를 다시 저장하는 것이다.

Scanner scanner = new Scanner(System.in);
int n = scanner.nextInt();
scanner.skip("(\r\n|[\n\r\u2028\u2029\u0085])?");

int remainder = 0; //나머지
int count=0 , back = 0;
while(n > 0){
    remainder = n % 2;
    n = n / 2;
   if(remainder == 1) {
      count++;
      if(count >= back) //Max value를 저장하는 것과 비슷
          back = count;   
   }else{
    count = 0;
   }
}
System.out.println(back);


2019년 4월 6일 토요일

Hackerrank Day 9 Recursion 3





알고리즘 연습 사이트
www.hackerrank.com


Day 9:Recursion 3

재귀 메소드 안에 특정조건까지는 자기자신을 호출하면서 프로그램이 동작하다가 재귀 호출을 끝내는 시점을 잘 지정해놓아야 무한 루프에 빠지지 않는다.

가장 기초적인 재귀 호출 연습으로 factorial 를 풀어보았다.
5! = 5 * 4 * 3 * 2 * 1 이런 규칙으로 연산이 되기 때문에 n자기자신이 1보다 큰 순간까지는 n 과 n-1의 곱을 리턴한다. n-1곱은 또다시 4! 이 되는 것이기 때문에 동일 작업이 반복되다가 n이 1이 되는 순간 return 1이 되면서 최초 호출한 factorial 메소드까지 return 값을 전달하게 된다.

static int factorial(int n) {
      if(n>1){
        return n * factorial(n-1);
      }else{
        return 1;
      }
}

factorial 구하는 메소드 사용법은 n을 원하는 숫자를 넣으면 된다.
int result = factorial(n);


2019년 4월 5일 금요일

Hackerrank Day 7 Arrays / Day 8 Dictionaries and Maps






알고리즘 연습 사이트
www.hackerrank.com


Day 7:Arrays

7일차 문제는 간단하였다.
배열에 들은 데이터를 역순으로 다시 출력하라는 문제였다.
역순으로 출력하기 위해 배열의 length의 -1 부터 시작하여 0이 될때까지 i를 감소시키면서 loop를 반복하면서 배열의 값을 뒤에서부터 출력해주면 된다.

for(int i = n-1; i>=0 ; i--){
    System.out.print(arr[i]);
    System.out.print(" ");
}


Day 8:Dictionaries and Maps

자바에서 Map은 key와 value의 쌍으로 데이터를 저장하는 자료구조이다.
사전을 떠올려보면 된다.
동일한 key에 대해 기존의 value를 교체 할 수도 있는데,
map.put("Hi","Bye"); 와 같이 key,value를 저장한 후 기본적으로 map.get("Hi"); 는 Bye값을 리턴하게 된다.
이런 상태에서 다시 map.put("Hi","Bye!!"); 를 넣으면 Hi라는 키값의 value가 Bye!!로 교체되게 된다.

8일차 문제는 전화번호부를 만드는 것이다. 이름을 key, 전화번호를 value로 잡고 map 에 저장한 후에 키값을 이용해 전화번호의 존재 여부를 체크한다.


Scanner in = new Scanner(System.in);
int n = in.nextInt();
Map<String,Integer> map = new HashMap<String,Integer>();
for(int i = 0; i < n; i++){
 String name = in.next();
 int phone = in.nextInt();
 map.put(name,phone);
}
while(in.hasNext()){
 String s = in.next();
 if(map.get(s) == null){
  System.out.println("Not found");
 }else{
  System.out.println(s+"="+map.get(s));
 }
}
in.close();

Hackerrank Day 6 Let's Review



알고리즘 연습 사이트
www.hackerrank.com


Day 6:Let's Review


* String and Characters

char 형을 강제로 int형으로 변환시키면 숫자가 나온다.
문자데이터 한개는 아스키코드 숫자에 매칭되어 있기 때문이다.
예를 들면 소문자 c를 int로 바꾸면 ASCII value 인 99 라는 숫자를 얻어 낼 수 있다.


* String.toCharArray()
API docs: https://docs.oracle.com/javase/7/docs/api/java/lang/String.html#toCharArray%28%29
toCharArray() 메소드는 String 클래스의 메소드이다. String 문자열을 Char 배열로 반환해준다. 문자열의 구성요소들을 다룰 때 유용할 것 같다.


6일차 문제는 Scanner로 숫자를 입력하면 그 라인 수만큼 문장 혹은 단어를 입력받는다.
그리고 한 String 객체를 구성하고 있는 문자 요소들의 짝수번째 문자와 홀수번째 문자를 각각 모은다.
짝수와 홀수번째의 새로 만들어진 문자열을 가운데 공백을 끼워넣고 합쳐서 출력하면 된다.

Scanner sc = new Scanner(System.in);
 int num = sc.nextInt();
 sc.nextLine();
 String[] sArr = new String[num];


 for(int i = 0 ; i < sArr.length;i++){
     sArr[i] = sc.nextLine();
 }


 for(String tmp : sArr){
     String even = "";
     String odd = "";
     char[] cArr = tmp.toCharArray();
     for(int i = 0 ; i < cArr.length ; i++){
  if(i%2==0){
      even += cArr[i];
  }else{
      odd += cArr[i];
  }
     }
     System.out.println(even + " " + odd);
 }

2019년 4월 4일 목요일

Hackerrank Day 4 Class vs. Instance / Day 5:Loops



알고리즘 연습 사이트
www.hackerrank.com


Day 4:Class vs. Instance


* 클래스와 인스턴스(=객체) 의 차이?
클래스는 인스턴스를 만들기 위한 설계도면 같은 것이다.
그냥 심플하게 텍스트라고 하면 될 것이다.

이렇게 작성해 놓은 클래스 파일을 이용하여 new 라는 키워드를 이용하면, 인스턴스를 생성 할 수 있게 되는데 인스턴스라는 것은 실제 컴퓨터 메모리 상에 적재된 상태를 뜻한다.

이번 문제는 Person 클래스를 생성하고 생성자에 parameter 를 주고 인스턴스 변수에 값을 대입한다. 
단, 나이는 0이상이어야 하므로 음수 값이 들어왔을 때 오류 메세지를 출력하고 0 을 대입한다.

amIOld메소드에 ternary operator를 이용하여 조건별 출력 문구를 다르게 하였다.
사용법은 if ? then : else 이런 형태이다.

public class Person {
        private int age; 
 public Person(int initialAge) {
          if(initialAge > 0){
            this.age = initialAge;
          }else{
            this.age = 0;
            System.out.println("Age is not valid, setting age to 0.");
          }
 }
 public void amIOld() {
           System.out.println(this.age<13 ? "You are young." : (this.age<18 ? "You are a teenager.": "You are old."));
 }
 public void yearPasses() {
           age++;
 }
}


Day 5:Loops

* Loops 종류
for , while , do~while 이 있다. 5일차 문제는 2를 입력하면 구구단 2단이 출력되게 하는 간단한 코드다.

너무 간단한 문제여서 5일째 문제는 4일째와 함께 작성하였다.

for(int i = 1 ; i < 11 ; i ++){
 System.out.println(n+" x "+ i +" = " + n*i);



Hackerrank Day 3 Intro to Conditional Statements



알고리즘 연습 사이트
www.hackerrank.com


Day 3:Intro to Conditional Statements


* if 문 조건 분기
if 문은 워낙 많이 쓰는 것이기 때문에 3일차 문제는 쉽게 넘어갔다.
짝수가 아니면 Weird를 출력하고, 짝수일 경우 아래의 조건처럼 출력하라는 문제다.

if(N%2!=0){
    System.out.println("Weird");
}else{
  if(2<=N && N<=5)
    System.out.println("Not Weird");
  else if(6<=N && N<=20)
    System.out.println("Weird");
  else if(N>20 )
    System.out.println("Not Weird");
}


Hackerrank Day 2 Operators



알고리즘 연습 사이트
www.hackerrank.com


Day 2:Operators


* Java 자료형의 연산
서로 다른 자료형끼리의 연산은 작은 자료형이 큰 자료형 쪽으로 자동 변환이 일어난다.
따라서 아래와 같은 다른 자료형끼리 연산 시 double 형이 큰 쪽이므로 결과가 double형으로 나타나게 된다.

double d1 = 10.25;
int i1 = 10;

System.out.println(d1 * i1 /100);
System.out.println(d1 + i1 );
result
1.025
20.25

큰 자료형에서 작은 자료형으로 강제 변환을 할 때에는 데이터 손실이 일어난다.

* 자료형 크기 참고

byte(1byte) < short(2byte) < int(4byte) < long(8byte) < float(4byte) < double(8byte)

그외 boolean(논리형,1byte) , char (문자형,2byte)

두번째 문제 답은 아래와 같이 작성하였다.
result를 double 로 지정하여 값 손실이 없게 한 후 Math.round 메소드로 결과를 반올림 한 후에 값 출력 요구사항은 소수점이 없어야 했으므로, int로 강제 캐스팅 처리하였다.

static void solve(double meal_cost, int tip_percent, int tax_percent) {
        double result =  meal_cost 
        + ( meal_cost * tip_percent / 100) 
        + ( meal_cost * tax_percent / 100 ) ;
        
        System.out.println((int)Math.round(result));
}

2019년 4월 1일 월요일

Hackerrank Day 1 Data Types


알고리즘 연습 사이트
www.hackerrank.com


Day 1:Data Types

Scanner Class API docs: https://docs.oracle.com/javase/8/docs/api/java/util/Scanner.html

* 기본 사용법
Scanner sc = new Scanner(System.in);
int i = sc.nextInt();

* Scanner Class 주의사항

int, double등 Scanner 클래스의 메소드로 입력을 받아들인 후에 문자열을 입력받기 위해 nextLine 메소드를 바로 호출하게 되면 입력했던 문자열이 출력이 안되고 빈 공백으로 출력된다.

그 이유는 직전에 nextDouble 호출 시 데이터 입력 후 enter로 인해 숨어 들어갔던 개행 문자열이 남아 있다.
nextLine 메소드가 뒤에 바로 호출 되면, nextLine은 개행 문자열이 나타날 때까지 읽어들이기 때문에 앞전의 개행 문자를 체크하자마자 실행을 끝내버린다.
따라서 아무 문자열도 출력되지 않는다.
고로 nextLine 을 한번 더 호출해주고 정상적인 문자열을 입력받으면 된다.
Scanner sc = new Scanner(System.in);

int i = sc.nextInt();
double d = sc.nextDouble();
sc.nextLine(); //read newline character 
String s = sc.nextLine();