비트 맵 법: 하나의 수가 40 억 개의 정수 에 있 는 지 판단 합 니까?
6917 단어 나 는 큰 공장 에 들 어 갈 것 이다.알고리즘
최근 에 한 문 제 를 보 았 습 니 다. 40 억 개의 중복 되 지 않 는 unsigned int 의 정 수 를 주 고 순 서 를 정 하지 않 은 다음 에 한 개의 수 를 주 었 습 니 다. 이 수가 그 40 억 개의 수 에 있 는 지 어떻게 신속하게 판단 합 니까?
해법
자 료 를 찾 아 보 니 이 문 제 는 텐 센트 의 면접 문제 로 현재 인터넷 에서 보편적으로 내 놓 은 답 은 두 가지 가 있다.
1. 주옥 같은 프로 그래 밍 방안
우 리 는 40 억 개의 숫자 중 하 나 를 32 비트 의 바 이 너 리 로 표시 하고 이 40 억 개의 숫자 를 하나의 파일 에 넣 기 시작 했다 고 가정 한다.
그리고 이 40 억 개의 수 를 두 가지 로 나눈다. 1. 최고 위 는 0 이다.2. 최고 위 는 1 이다.
그리고 이 두 가 지 를 각각 두 파일 에 기록 합 니 다. 그 중에서 한 파일 의 갯 수 는 < 20 억, 다른 하 나 는 > 20 억 (이것 은 절반 에 해당 합 니 다) 입 니 다.
찾 을 수의 가장 높 은 위치 와 비교 한 다음 해당 파일 에 들 어가 서 찾 습 니 다.
그 다음 에 이 파일 을 두 가지 로 나 누 었 습 니 다. 1. 차 의 최고 위 는 0 입 니 다.2. 차 최고 위 는 1 이다.
그리고 이 두 가 지 를 각각 두 파일 에 기록 합 니 다. 그 중에서 한 파일 의 개수 < = 10 억, 다른 하 나 는 > = 10 억 (이것 은 절반 에 해당 합 니 다).찾 을 수의 최고 위 치 를 비교 한 다음 해당 파일 에 들 어가 서 찾 습 니 다.
.......
이런 식 으로 유추 하면 찾 을 수 있 고 시간 복잡 도 는 O (logn) 이다.
이 방안 은 본 고가 말 하고 자 하 는 중점 이 아니 라, 단지 사고방식 을 여기에 놓 아 모두 가 참고 하도록 제공 할 뿐이다.
2. 비트 맵
사고의 방향
우리 가 40 억 개의 숫자 를 메모리 에 직접 읽 어 처리 할 수 없 는 이 유 는 40 억 개의 unsigned int 의 정수 가 약 15G 메모 리 를 차지 하기 때 문 입 니 다. 정상 적 인 상황 에서 이렇게 큰 메모리 가 없 으 면 이렇게 할 수 없습니다.
이런 상황 은 하나의 정수 가 4 개의 바이트 (Byte) 를 차지 하기 때문에 이 문제 에서 우 리 는 사실 특정한 숫자 가 존재 하 는 지 에 만 관심 을 가진다. 이런 상황 에서 우 리 는 비트 맵 법 을 통 해 이 문 제 를 해결 할 수 있다.
비트 맵 사상: 40 억 개의 unsigned int 에 대해 의 정수, 각 숫자 는 1 개의 바 이 너 리 (1 개의 바 이 너 리 수 는 1Bit, 1Byte = 8Bit) 로 이 숫자 가 존재 하 는 지, 0 은 존재 하지 않 는 지, 1 은 존재 하 는 지 를 나타 낸다.낮은 자리 부터 세 기 를 시작 합 니 다:
첫 번 째 이 진 수 는 정수 0 이 존재 하 는 지 여 부 를 나타 낸다.
두 번 째 이 진 수 는 정수 1 이 존재 하 는 지 여 부 를 나타 낸다.
세 번 째 이 진 수 는 정수 2 가 존재 하 는 지 여 부 를 나타 낸다.
순서대로 유추 하 다.
제4 294967296 개의 이 진 수 는 정수 4294967295 의 존재 여 부 를 나타 내 는 데 쓰 인 다.
unsigned int 는 32 & 64 비트 컴 파일 러 의 범 위 는 0 ~ 4294967295 이 고 4294967296 개의 바 이 너 리 수 는 약 512 M 메모 리 를 차지 하 며 받 아들 일 수 있 는 범위 이다.
예시
제목: 우 리 는 3 개의 정 수 를 읽 었 다. 1, 2, 4. 정수 3 이 읽 혔 는 지 판단 해 야 한다.
해답 과정:
1) 40 억 개의 unsigned int 에 대해 의 정 수 는 4294967296 개의 바 이 너 리 수 를 정의 할 수 있 고 모든 초기 화 값 은 0 입 니 다.
2) 읽 기 정수 1: 두 번 째 바 이 너 리 할당 값 을 1 로 하여 정수 1 이 존재 한 다 는 것 을 나타 낸다. 이때 값 은 10 (높 은 자리 에 4294967294 개 0 이 있 는데 읽 기 편 하도록 쓰 지 않 으 면 다음 과 같다) 이다.
3) 읽 기 정수 2: 세 번 째 바 이 너 리 할당 값 을 1 로 하여 정수 2 가 존재 한 다 는 것 을 나타 낸다. 이때 값 은 110 이다.
4) 읽 기 정수 4: 다섯 번 째 바 이 너 리 할당 값 을 1 로 하여 정수 4 가 존재 한 다 는 것 을 나타 낸다. 이때 값 은: 10110 이다.
5) 정수 3 이 읽 혔 는 지 여 부 를 판단 한다. 첫 번 째 이 진 수 는 정수 0 이 존재 하 는 지 여 부 를 나타 내기 때문에 정수 3 은 네 번 째 이 진 수 를 통 해 표시 한다. 이때 의 값 은 10110 이 고 네 번 째 이 진 수 는 0 이기 때문에 정수 3 은 읽 힌 적 이 없다.
코드 구현
자바 에서 바 이 너 리 수 를 직접 조작 할 수 없 기 때문에 int 를 통 해 이 루어 질 수 있 습 니 다.1 개 이 진수 점용 1 Bit;1 개의 int 는 4 Byte, 즉 32 비트 를 차지한다.따라서 우 리 는 1 개의 int 를 사용 하여 32 개의 이 진 수 를 표시 할 수 있다.
그래서 우 리 는 다음 과 같은 생각 이 있다.
첫 번 째 int 는 정수 0 ~ 31 이 존재 하 는 지,
두 번 째 int 는 정수 32 ~ 63 이 존재 하 는 지,
세 번 째 int 는 정수 64 ~ 95 가 존재 하 는 지 여 부 를 유추 한다.
따라서 우 리 는 최종 적 으로 하나의 int 배열 을 사용 하여 4294967296 개의 바 이 너 리 수 를 표시 하고 배열 의 아래 표 시 를 통 해 몇 번 째 int 를 표시 할 수 있다.
코드 는 다음 과 같다.
package com.joonwhee.open.leetcode.temp;
/**
*
*
* @author joonwhee
* @date 2019/1/22
*/
public class BitMap {
/**
* ,
* unsigned int 4294967295, length 4294967296
*/
private long length;
/**
*
*/
private static int[] bitmapBucket;
/**
* int 32 ,
* BIT_VALUE[0] 1 、
* BIT_VALUE[1] 2 ,
*
* BIT_VALUE[0] = 00000000 00000000 00000000 00000001
* BIT_VALUE[1] = 00000000 00000000 00000000 00000010
* BIT_VALUE[2] = 00000000 00000000 00000000 00000100
* ...
* BIT_VALUE[31] = 10000000 00000000 00000000 00000000
*/
private static final int[] BIT_VALUE = {
0x00000001, 0x00000002, 0x00000004, 0x00000008,
0x00000010, 0x00000020, 0x00000040, 0x00000080,
0x00000100, 0x00000200, 0x00000400, 0x00000800,
0x00001000, 0x00002000, 0x00004000, 0x00008000,
0x00010000, 0x00020000, 0x00040000, 0x00080000,
0x00100000, 0x00200000, 0x00400000, 0x00800000,
0x01000000, 0x02000000, 0x04000000, 0x08000000,
0x10000000, 0x20000000, 0x40000000, 0x80000000};
/**
* length 1 - 32: 1
* length 33 - 64: 2
* ...
*
*
* @param length
*/
public BitMap(long length) {
this.length = length;
// ,
bitmapBucket = new int[(int) (length >> 5) + ((length & 31) > 0 ? 1 : 0)];
}
/**
* number
*
* @param number
* @return true: number , false: number
*/
public boolean getBit(long number) {
if (number < 0 || number > length) {
throw new IllegalArgumentException(" ");
}
// number
int belowIndex = (int) (number >> 5);
// number ,( 32 , 0 - 31)
int offset = (int) (number & 31);
//
int currentValue = bitmapBucket[belowIndex];
// number
return ((currentValue & BIT_VALUE[offset])) == 0 ? false : true;
}
/**
* number
*
* @param number
*/
public void setBit(long number) {
//
if (number < 0 || number >= length) {
throw new IllegalArgumentException(" ");
}
// number
int belowIndex = (int) (number >> 5);
// number ,( 32 , 0 - 31)
int offset = (int) (number & 31);
//
int currentValue = bitmapBucket[belowIndex];
// number
bitmapBucket[belowIndex] = currentValue | BIT_VALUE[offset];
}
public static void main(String[] args) {
BitMap bitMap = new BitMap(4294967296L);
bitMap.setBit(4294967295L);
System.out.println(bitMap.getBit(4294967295L));
System.out.println(bitMap.getBit(4294967294L));
}
}
사고방식 을 이해 한 후에 코드 는 비교적 간단 해 졌 다.
1) 구조 함수 가 전달 하 는 length 값 을 통 해 충분 한 int 배열 bitmapBucket 을 구축 하고 제목 의 unsigned int 의 정수 에 대해 length 는 4294967296 으로 충분 합 니 다.
2) 주어진 수 40 억 개 를 setBit 방법 으로 대응 하 는 위치의 이 진 수 를 1 (1 은 존재 함) 로 표시 한다.
3) getBit 로 방법 은 주어진 number 가 이전의 40 억 개 수 에 존재 하 는 지 여 부 를 판단 한다.
setBit 예: 예 를 들 어 우 리 는 정수 32 를 존재 로 표시 해 야 합 니 다.
1) 먼저 정수 32 가 있 는 비트 맵 통 아래 표 시 된 것 을 1 로 계산 하면 bitmapBucket [1] 이다.
2) 이어서 정수 32 를 계산한다 bitmapBucket 에서 [1] 통 의 아래 표 시 는 0 이다.
3) bitmapBucket [1] 현재 값 currentValue 를 가 져 옵 니 다.
4) 마지막 으로 우 리 는 bitmapBucket [1] 을 통 의 첫 번 째 바 이 너 리 수 를 1 로 표시 하고 이전에 표 시 된 바 이 너 리 수 에 영향 을 주지 않 기 때문에 currentValue 0000 0000 0000 0000 0001 혹은 연산 하면 된다.그리고 모든 이 진수 에 대해 우 리 는 BIT 를 통 해VALUE 는 이쪽 0000 0000 0000 0000 0000 0001, BIT 를 통 해VALUE [0] 가 표시 합 니 다.
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
【JavaScript】 볼록함 그라함 스캔을 구현, 애니메이션화한다! ? 【canvas】볼록포를 시각화해 본다. — s-yoshiki | 스크립트 카스 (@s_yoshiki_dev) JavaScript에서 그레이엄 스캔에 의해 정렬되어 가는 애니메이션을 구현했다. 아래쪽에서 데모로 소개. 참고 Java...
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.