LeetCode 문제 중 난이도 EasyMove Zeroes이다. 문제 링크는 포스팅의 맨 마지막에 추가하였다. 언어는 Java를 사용했다.



  문제해석


주어진 배열 nums의 모든 0 값들을 뒤쪽으로 이동시키면서 0이 아닌 값의 순서는 그대로 유지하는 함수를 작성해라.

* nums의 복사본인 새로운 배열을 생성하지 않고 nums배열에서 작업한다

* 전체 연산의 수를 최소화한다




첫번째 방법은 가장 처음으로 0이 나오는 값의 인덱스를 구한다. 그리고 0의 인덱스값 뒤에 오는 요소들 중 처음으로 나오는 0이 아닌 숫자를 0의 인덱스에 넣고 숫자가 있던 자리는 0으로 바꾼다. 배열의 값이 0인 인덱스들에 같은 행위를 반복한다.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
class Solution {
    public void moveZeroes(int[] nums) {
        
        int indexOfZero=-1;
        
        //맨처음 0을 찾아서 index값 가져옴
        for(int i=0 ; i<nums.length ; i++){
            if(nums[i]==0){
                indexOfZero=i;
                break;
            }
        }
        
        //0이 없으면 그대로 리턴
        if(indexOfZero==-1return;
        
        //0이 있는곳으로 뒤에서 0이 아닌수를 가져오고 index를 하나 늘린다(반복)
        for(int i=zeroIndex ; i<nums.length ; i++){
            if(nums[i]==0continue;
                nums[indexOfZero]=nums[i];
                nums[i]=0;
                indexOfZero++;
        }
    }
}
cs

시간복잡도는 O(n), 공간복잡도는 O(1)이다. 이 방법은 경우에 따라 불필요한 추가연산을 하게 되는 경우가 있다. 아래 예시를 보자.


만일 nums가 [1, 0, 2, 4, 5, 0]라고 가정해보자. 그럼 연산순서는 아래와 같을 것이다.

[1, 0, 2, 4, 5, 0] -> [1, 2, 0, 4, 5, 0] -> [1, 2, 4, 0, 5, 0] -> [1, 2, 4, 5, 0, 0]

nums[2]에 0을 넣었다가 다시 4로 바꾸고 nums[3]도 0을 넣었다가 다시 5로 바꾼다.





두번째 방법은 배열을 탐색하면서 0이 아닌 숫자들을 앞에서부터 순서대로 집어넣고 그 뒤를 0으로 채우는 것이다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
class Solution {
    public void moveZeroes(int[] nums) {
        
        int index=0;
        
        //0이 아닌 숫자를 찾아서 앞에서부터 하나씩 채운다
        for(int i=0 ; i<nums.length ; i++){
            if(nums[i]!=0){
                nums[index]=nums[i];
                index++;
            }
        }
        
        //index뒤를 전부 0으로 바꾼다
        while(index<nums.length){
            nums[index]=0;
            index++;
        }
    }
}
cs

이렇게 하면 특정 위치의 값을 두번씩 바꾸는 일은 없겠지만 0의 갯수가 많을수록 0을 채워넣는 연산이 중복되는 경우가 생긴다(0을 또다시 0으로 채우는 경우). 이 방법도 동일하게 시간복잡도는 O(n), 공간복잡도는 O(1)이다.


문제출처 - https://leetcode.com/problems/move-zeroes/




LeetCode 문제 중 난이도 EasyContains Duplicate이다. 문제 링크는 포스팅의 맨 마지막에 추가하였다. 언어는 Java를 사용했다.



  문제해석


정수 배열을 입력값으로 받아 해당 배열이 중복값을 포함하고 있는지 판별하라.

아무 값이나 배열 내에서 두번 이상 나타나는 값이 있다면 true를 리턴하고 모든 요소가 유일하다면 false를 리턴해라.







첫번째 방법은 배열을 정렬한 후 앞뒤 값을 비교하는 것이다. 이전에 포스팅한 Single Number 문제의 첫번째 풀이법과 원리가 같다.


2019/03/16 - [프로그래밍문제풀기] - [코딩연습] Single Number 하나뿐인 숫자 찾기




1
2
3
4
5
6
7
8
9
10
11
12
13
14
class Solution {
    public boolean containsDuplicate(int[] nums) {
        
        Arrays.sort(nums);
        
        for(int i=0 ; i<nums.length-1 ; i++){
            //앞뒤 값이 같은게 나오면 true리턴
            if(nums[i] == nums[i+1]) return true;
        }
        
        //for문을 빠져나와 전체 배열을 다 돌때까지 중복이 없으면 false리턴
        return false;
    }
}
cs


정렬하는데 드는 시간 O(nlogn), 탐색하는데 드는 시간 O(n)으로 시간복잡도는 O(nlogn)이고 추가적인 메모리 사용이 없으므로 공간복잡도는 O(1)이다.





두번째 방법은 Set 자료구조를 이용하는 것이다. Set은 중복된 데이터를 허용하지 않는 집합이다. 만약 nums에 중복된 값이 있다면 nums의 길이와 numset의 사이즈가 다를 것이다.

ex) nums = [3,7,7,8,6] 일 경우 nums.length=5, numSet.size()=4


1
2
3
4
5
6
7
8
9
10
11
12
13
class Solution {
    public boolean containsDuplicate(int[] nums) {
        
        Set<Integer> numSet = new HashSet<>();
        
        for(int i=0 ; i<nums.length ; i++){
            numSet.add(nums[i]);
        }
        
        //배열의 길이와 배열의 요소를 모아놓은 집합의 크기가 다르면 true, 같으면 false 리턴
        return nums.length != numSet.size();
    }
}
cs



이 방법은 배열을 한번만 탐색하므로 시간복잡도는 O(n)이지만 numSet이라는 추가적인 공간을 사용하므로 공간복잡도는 O(n)이다.





문제 출처 - https://leetcode.com/problems/contains-duplicate/






LeetCode 문제 중 난이도 EasySymmetric Tree이다. 문제 링크는 포스팅의 맨 마지막에 추가하였다. 언어는 Java를 사용했다.





  문제해석

주어진 이진 트리를 가지고 해당 트리가 거울에 비친 자신과 같은지(가운데를 중심으로 대칭인지) 판별하라.








트리는 모든 노드들이 연결되어있고 순환이 존재하지 않는 그래프이다.

나무(tree)를 거꾸로 그린 모양의 계층구조를 생각해보자. 트리(tree) 자료구조는 뿌리(root node)에서 시작해 가지가 뻗어 나가며 맨 끝에는 잎(leaf node)이 달려 있다. 우리가 잘 아는 트리구조가 있는데 바로 회사의 조직도와 컴퓨터 디렉토리이다.








아래 그림은 이진 트리(binary tree)의 예이다. 예시를 보며 몇가지 기본적인 트리 용어를 알아보자.


* 이진트리(binary tree) : 트리 중에서 각 노드의 자식 노드의 수가 2개 이하인 트리



Node(A,B,C...J) : 트리의 구성요소에 해당하는 요소들


Root Node(A) : 최상위 노드


Parent Node : 어떤 노드의 상위 노드

A는 B와 C의 부모노드이고 B와 C도 각각 D&E, F&Gd의 부모노드이다


Child Node : 어떤 노드의 하위 노드

F와 G는 C의 자식노드이고 H와 I는 E의 자식노드이다


Subtree : 어떤 노드의 부모 노드의 집합

D의 조상은 B,A이고 J의 조상은 G,C,A이다


Descendant of a node : 어떤 노드의 자식노드들의 집합

C의 자손은 F,G,J이고 A 자손은 자기자신을 제외한 전체 노드들이다


Leaf Node(D,H,I,F,J) : 자식노드가 존재하지 않는 노드


Subtree : 어떤 트리의 안에 있는 작은 트리

트리 T의 서브트리 S는 T의 노드 중 하나와 그의 자손들로 이루어진 트리


Depth of a node : 어떤 노드의 루트노드까지의 조상의 수

루트노드의 depth는 0이고 G의 depth는 2이다


Height of a tree : 해당 트리가 가진 노드들의 depth중 최댓값






다시 문제로 돌아가보자. 트리가 좌우 대칭이려면 루트노드를 중심으로 왼쪽 서브트리를 좌우대칭한 것이 오른쪽 서브트리와 같아야 한다. 그러려면 왼쪽 서브트리의 왼쪽 자식노드오른쪽 서브트리의 오른쪽 자식노드의 값이 같아야 하고 왼쪽 서브트리의 오른쪽 자식노드오른쪽 서브트리의 왼쪽 자식노드의 값이 같아야 한다.



같은방식으로 자손노드들을 리프노드까지 탐색한다. 코드로 나타내면 다음과 같다.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
class Solution {
    public boolean isSymmetric(TreeNode root) {
        
        return isMirror(root,root);
    }
    
    public boolean isMirror(TreeNode t1, TreeNode t2) {
        
        //t1과 t2가 둘다 null이면 true
        if(t1 == null && t2 == nullreturn true;
        
        //t1,t2중에 하나만 널이면 양쪽이 같지 않으므로 false
        if(t1 == null || t2 == nullreturn false;
        
        //t1과 t2의 값이 달라도 false
        if(t1.val != t2.val) return false;
        
        return isMirror(t1.left,t2.right) && isMirror(t1.right,t2.left);
    }
}
cs


13번째 줄의 (t1 == null || t2 == null)는 위에서 이미 둘다 null인 경우를 체크했으므로 t1이나 t2가 둘중 하나만 null인 경우를 체크한다.



이 방법의 시간복잡도는 O(n)이고 공간복잡도의 worse case는 트리가 일직선으로 이루어져 Height가 O(n)인 경우이므로 O(n)이다.




문제 출처 - https://leetcode.com/problems/symmetric-tree/



+ Recent posts