스터디사이트 : https://www.hackerrank.com
JAVA Basic : bitwise AND(비트연산 AND)
주어진 숫자배열 (1부터 1씩 증가한 숫자가 요소로 있는 집합. S={1, 2, 3, ... , N} ) 중 두 개의 요소(A, B)를 추출하여,
A와 B의 AND 비트연산을 한 결과가 주어진 숫자보다 작으면서, 그 중에서 가장 큰 숫자를 구하라.
입력
3 ← T : 테스트 케이스들의 갯수. 아래 라인수를 보다시피 3라인, 테스트 케이스도 3.
5 2 ← (테스트케이스1) N K : ⓝ-S 집합의 가장 마지막 요소가 올 수. S={1,2,3,4,5} ⓚ-AND 비트연산결과의 최대값을 정하는 수
8 5 ← (테스트케이스2) N K
2 2 ← (테스트케이스3) N K
출력
1 ← 테스트케이스1 : 주어진 N, K 의 수 조건에 따라 최대 수를 출력.
4 ← 테스트케이스2 : 주어진 N, K 의 수 조건에 따라 최대 수를 출력.
0 ← 테스트케이스3 : 주어진 N, K 의 수 조건에 따라 최대 수를 출력.
※ 조건
1 <= T <= 10^3
2 <= N <= 10^3
2 <= K <= N
이건 2진수 AND 연산이였다..
단순 10진수의 AND 연산인 줄 알고
왜 1과 2를 곱했는데 0이 나오고 1과 3을 곱했는데 1이 나올까... 많이 고민했었다..
역시 언어는 언어.. 자주 써야 2진수라는 걸 바로 알텐데..ㅋ
시범 예
N=5, K=2 ▷▶ S={1,2,3,4,5}
1. |
A=1, B=2 ▷▶ A&B = 0 |
A = 001 B = 010 A&B =000 |
2. |
A=1, B=3 ▷▶ A&B = 1 |
A = 001 B = 011 A&B =001 |
3. |
A=1, B=4 ▷▶ A&B = 0 |
A = 001 B = 100 A&B =000 |
4. |
A=1, B=5 ▷▶ A&B = 1 |
A = 001 B = 101 A&B =001 |
5. |
A=2, B=3 ▷▶ A&B = 2 |
A = 010 B = 011 A&B =010 |
6. |
A=2, B=4 ▷▶ A&B = 0 |
A = 010 B = 100 A&B =000 |
7. |
A=2, B=5 ▷▶ A&B = 0 |
A = 010 B = 101 A&B =000 |
8. |
A=3, B=4 ▷▶ A&B = 0 |
A = 011 B = 100 A&B =000 |
9. |
A=3, B=5 ▷▶ A&B = 1 |
A = 011 B = 101 A&B =001 |
10. |
A=4, B=5 ▷▶ A&B = 4 |
A = 100 B = 101 A&B =100 |
10진수를 2진수로 변환하기
이전에 포스팅 해 놓은게 있다.. 오랜만에 보네? ㅋ
http://geoseong.tistory.com/14
오랜만에 2진수 변환하다보면 헷갈리는 소인수분해(?) 원리..
디버깅 1
| |||
결과 : [repeat 1] S[0] : 1 S[1] : 2 S[2] : 3 S[3] : 4 S[4] : 5 [repeat 2] S[0] : 1 S[1] : 2 S[2] : 3 S[3] : 4 S[4] : 5 S[5] : 6 S[6] : 7 S[7] : 8 [repeat 3] S[0] : 1 S[1] : 2 | |||
▷ Feedback : 가볍게 T 와 N 을 이용해서 숫자집합인 S에 숫자를 집어넣어봤다. temp변수는 단지 디버깅을 하기위해 정의했으므로 무시해도 된다. 이제 10진수를 2진수로 변환을 하는 코딩을 하면서 A와 B를 추출해야된다. |
디버깅 2
| |||
결과 : [repeat 1] S[0] : 1 S[1] : 2 S[2] : 3 S[3] : 4 S[4] : 5 a : 1, b : 2 / a : 1, b : 3 / a : 1, b : 4 / a : 1, b : 5 / a : 2, b : 3 / a : 2, b : 4 / a : 2, b : 5 / a : 3, b : 4 / a : 3, b : 5 / a : 4, b : 5 / [repeat 2] S[0] : 1 S[1] : 2 S[2] : 3 S[3] : 4 S[4] : 5 S[5] : 6 S[6] : 7 S[7] : 8 a : 1, b : 2 / a : 1, b : 3 / a : 1, b : 4 / a : 1, b : 5 / a : 1, b : 6 / a : 1, b : 7 / a : 1, b : 8 / a : 2, b : 3 / a : 2, b : 4 / a : 2, b : 5 / a : 2, b : 6 / a : 2, b : 7 / a : 2, b : 8 / a : 3, b : 4 / a : 3, b : 5 / a : 3, b : 6 / a : 3, b : 7 / a : 3, b : 8 / a : 4, b : 5 / a : 4, b : 6 / a : 4, b : 7 / a : 4, b : 8 / a : 5, b : 6 / a : 5, b : 7 / a : 5, b : 8 / a : 6, b : 7 / a : 6, b : 8 / a : 7, b : 8 / [repeat 3] S[0] : 1 S[1] : 2 a : 1, b : 2 / | |||
▷ Feedback : S 배열에서 A와 B를 추출하되, A < B 의 공식을 충족하는 코딩을 했다. 이 코딩을 하면서 몇달전에 시험 본 정보처리기사의 알고리즘에서 반복문을 두번 하는 것이 떠올랐다.ㅋ |
디버깅 3
| |||
결과 : [repeat 1] S[0] : 1 S[1] : 2 S[2] : 3 S[3] : 4 S[4] : 5 a : 1, b : 2 / binary - 1 a : 1, b : 3 / binary - 1 a : 1, b : 4 / binary - 1 a : 1, b : 5 / binary - 1 a : 2, b : 3 / a의 몫 : 1, a의 나머지 : 0 binary - 10 a : 2, b : 4 / a의 몫 : 1, a의 나머지 : 0 binary - 10 a : 2, b : 5 / a의 몫 : 1, a의 나머지 : 0 binary - 10 a : 3, b : 4 / a의 몫 : 1, a의 나머지 : 1 binary - 11 a : 3, b : 5 / a의 몫 : 1, a의 나머지 : 1 binary - 11 a : 4, b : 5 / a의 몫 : 2, a의 나머지 : 0 a의 몫 : 1, a의 나머지 : 0 binary - 100 | |||
▷ Feedback : 여기까지는 a만 2진수로 변환하는 과정을 코딩해봤다.. 그런데 binary라는 변수가 String으로 놓으면 안된다는 것을 깨달았다. 왜냐하면 완성된 2진수가 String 변수면, AND계산할 때 String끼리 어떻게 계산하나?? ㅋ AND연산이니까 각 자릿수가 0 아니면 1이 서로 맞으면 1이고 아니면 0이기 때문에 String[] 배열에다가 2진수 숫자 하나씩 넣고 비교하는게 맞는거같기도 하다. |
머릿속에 정리가 잘 안되어서 엑셀에다가 본격적인 디버깅을 돌려보았다..
그러니까 코딩들을 그나마 간소화 시킬 수 있게 되었다!!
① 차라리 A와 B를 동시에 진행하다가 A의 나머지와 B의 나머지를 곱한 결과를 스택에 넣는다.
② 10진수로 변환을 해야..
다시 pop()하면 일의자리수부터 2진수가 나오는데, 그 수에다가 2^0, 2^1 순차적으로 곱한 후 합한다.
③ 이 합한 10진수가 지정한 K보다 크냐?
크다면 {
목록변수에다가 넣는다.
④ 그리고 그 목록들 중 제일 큰 수를 찾기
0번지를 제일큰놈으로 지정하고
순차적으로 번지수를 찾아가 0번지보다 큰놈이면 그놈이 큰놈으로 바뀌고
마지막 번지수까지 찾아가서 남아있는 큰놈이 젤 큰놈이다
디버깅 4
| |||
결과 : [repeat 1] a : 1, b : 2 / A의 몫 : 0, A의 나머지 : 1 B의 몫 : 1, B의 나머지 : 0 A의 몫 : 0, A의 나머지 : 0 B의 몫 : 0, B의 나머지 : 1 num은 : 0 stacksize : 1 1번째 자리의 10진수 :0 현재까지의 총합 : 0 -------------- num은 : 0 stacksize : 0 0번째 자리의 10진수 :0 현재까지의 총합 : 0 -------------- a : 1, b : 2의 total : 0 ------------------------------ a : 1, b : 3 / A의 몫 : 0, A의 나머지 : 1 B의 몫 : 1, B의 나머지 : 1 A의 몫 : 0, A의 나머지 : 0 B의 몫 : 0, B의 나머지 : 1 num은 : 0 stacksize : 1 1번째 자리의 10진수 :0 현재까지의 총합 : 0 -------------- num은 : 1 stacksize : 0 0번째 자리의 10진수 :1 현재까지의 총합 : 1 -------------- a : 1, b : 3의 total : 1 ------------------------------ | |||
▷ Feedback : 디버깅을 하면서 깨달은 ①번과 ②번과정까지 했다. 으아 매우 오래걸렸따 ㅋㅋ 문제는 쉬워보였지만 여러 기술들의 집합이다.. 스택을 썼고, 10진수를 2진수로 변환하고, AND연산 한 2진수를 10진수로 다시 변환했다.. 이제 ArrayList나 다시 LinkedList같은곳에 AND연산 결과 10진수값을 집어넣고 비교하는 일이 남았다. 아! 그런데 생각해보니 꼭 ③, ④번 처럼 ArrayList를 만들어서 반복해갖고 한자리씩 검사할 필요가 없다. 왜냐하면 반복을 하면서 하나씩 A&B에 대한 total값이 생기므로, 새로운 저장공간을 만들어서 total값을 임시로 저장시킨다. 그리고 다음 반복문을 돌려서 나온 A&B에 대한 total값과 새로운 저장공간(이전 반복문으로 나온 total값)을 비교해서, 가장 큰 값을 구하는데, 주어진 K값보다 작으면 출력시키면 된다.. ㅋ 아래는 전체적인 코딩에 대한 반복문과 조건문을 간략히 정리해봤다. |
디버깅5
| |||
결과 : [repeat 1] a : 1, b : 2 / k : 2, a : 1, b : 2의 total : 0 ------------------------------ a : 1, b : 3 / k : 2, a : 1, b : 3의 total : 1 ------------------------------ 이제 total_max는 total의 수이다. total_max : 1 a : 1, b : 4 / k : 2, a : 1, b : 4의 total : 0 ------------------------------ a : 1, b : 5 / k : 2, a : 1, b : 5의 total : 1 ------------------------------ a : 2, b : 3 / k : 2, a : 2, b : 3의 total : 2 ------------------------------ a : 2, b : 4 / k : 2, a : 2, b : 4의 total : 0 ------------------------------ a : 2, b : 5 / k : 2, a : 2, b : 5의 total : 0 ------------------------------ a : 3, b : 4 / k : 2, a : 3, b : 4의 total : 0 ------------------------------ a : 3, b : 5 / k : 2, a : 3, b : 5의 total : 1 ------------------------------ a : 4, b : 5 / k : 2, a : 4, b : 5의 total : 4 ------------------------------ 해당 케이스의 total_max는 : 1 [repeat 2] ... | |||
▷ Feedback : 이제 디버깅 주석을 빼고 해보자.. |
디버깅6
| |||
결과 : 1 4 0 | |||
▷ Feedback : 그런데.. 다른 케이스를 입력하고 돌려보면 TimeOut이 뜬다. 162줄의 케이스는 잘되는데.. 176줄의 케이스는 TimeOut이다.. 그러던 중.. 다른 사람이 한 놀라운 코딩을 발견했다. |
결과1
| |||
결과 : 1 4 0 | |||
▷ Feedback : 2진수를 10진수로, 10진수를 2진수로 변환하지 않아도 저렇게 할수있다.. 나는 바보였돠... |
결과2
| ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
결과 : 1 4 0 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
▷ Feedback : 나머지, 몫, total_max 등을 구하기 위한 반복문이 다 배제되었다.. 무슨 원리로 저렇게 한 건지 잘 이해가 안간다.. k%2=0이면 짝수, k%2=1이면 홀수가 된다... ※ 조건 1 <= T <= 10^3 2 <= N <= 10^3 2 <= K <= N k가 홀수이고, k-1이 짝수라면..
위의 조건에 따라 적용하면, ( (k-1) | k ) <= n 도 true라는 것을 알 수 있다. k가 짝수이고, k-1이 홀수라면.. 그리고 ( (k-1) | k ) <= n 이 TRUE 이면 k-1 이 된다.... 음... 아래는 설명의 원본이다. 근데 읽어도 당최 이해가안된다.. 이해가시면 누가 설명좀해주세요.. ㅋ |
'JAVA > JAVA Basic' 카테고리의 다른 글
JAVA Basic : 정규식 , 문자열 비교 및 오름차순 정렬 (0) | 2016.10.05 |
---|---|
JAVA Basic : 중첩 로직 (0) | 2016.10.02 |
JAVA Basic : 제네릭 (0) | 2016.07.27 |
JAVA Basic : 인터페이스 (0) | 2016.07.18 |
JAVA Basic : 예외처리 - throw (0) | 2016.07.17 |