구 1 - n 직접 1 출현 횟수
예 를 들 어 12 를 입력 하면 1 부터 12 까지 이 정수 에 1 이 포 함 된 숫자 는 1, 10, 11, 12 로 1 이 모두 5 번 나 왔 다.
분석: 널리 알려 진 구 글 면접 문제 다.가장 직관 적 인 방법 으로 해답 을 구 하 는 것 은 그리 어렵 지 않 지만 유감스럽게도 효율 이 높 지 않다.효율 이 높 은 알고리즘 을 얻 으 려 면 비교적 강 한 분석 능력 이 필요 하고 쉬 운 일이 아니다.물론 구 글 의 면접 문제 중 간단 한 것 도 몇 개 없다.
먼저 우 리 는 가장 직관 적 인 방법 을 살 펴 보고 각각 1 에서 n 까지 의 정수 중 1 이 나타 나 는 횟수 를 구한다.한편, 하나의 정 수 를 구 하 는 십 진법 은 중 1 이 나타 난 횟수 를 나타 내 면 본 시험 시리즈 의 22 번 째 문제 와 비슷 하 다.우 리 는 매번 정수 의 비트 숫자 가 1 인지 아 닌 지 를 판단 한다.이 숫자 가 10 보다 크 면 10 을 나 눈 후에 한 자리 숫자 가 1 인지 아 닌 지 를 판단 한다.이 사고방식 을 바탕 으로 다음 과 같은 코드 를 쓰기 어렵 지 않다.
int NumberOf1(unsigned int n);
/////////////////////////////////////////////////////////////////////////////
// Find the number of 1 in the integers between 1 and n
// Input: n - an integer
// Output: the number of 1 in the integers between 1 and n
/////////////////////////////////////////////////////////////////////////////
int NumberOf1BeforeBetween1AndN_Solution1(unsigned int n)
{
int number = 0;
// Find the number of 1 in each integer between 1 and n
for(unsigned int i = 1; i <= n; ++ i)
number += NumberOf1(i);
return number;
}
/////////////////////////////////////////////////////////////////////////////
// Find the number of 1 in an integer with radix 10
// Input: n - an integer
// Output: the number of 1 in n with radix
/////////////////////////////////////////////////////////////////////////////
int NumberOf1(unsigned int n)
{
int number = 0;
while(n)
{
if(n % 10 == 1)
number ++;
n = n / 10;
}
return number;
}
이 사고방식 의 매우 뚜렷 한 단점 은 모든 숫자 가 1 이 이 숫자 에 나타 난 횟수 를 계산 해 야 하기 때문에 시간 복잡 도 는 O (n) 이다.입력 한 n 이 매우 클 때 대량의 계산 이 필요 하고 연산 효율 이 매우 낮다.우 리 는 불필요 한 계산 을 피하 기 위해 규칙 을 찾 아 보 았 다.
우 리 는 조금 큰 숫자 21345 를 예 로 들 어 분석 했다.우 리 는 1 부터 21345 까지 의 모든 숫자 를 2 단, 즉 1 - 1235 와 1346 - 21345 로 나 누 었 다.
1346 - 21345 중 1 이 나 온 횟수 를 먼저 살 펴 보 자.1 의 출현 은 두 가지 상황 으로 나 뉜 다. 하 나 는 1 이 최고 (만 위) 에 나타난다.1 부터 21345 까지 의 숫자 중 1 은 10000 - 1999 라 는 10000 개의 숫자 만 자리 에 나타 나 모두 10000 (104) 번 이 나 타 났 다.또 다른 경 우 는 1 이 최고 위 를 제외 한 다른 자리 에 나 타 났 다.예 를 들 어 1346 - 21345. 이 20000 개의 숫자 중 뒤의 네 자리 중 1 이 나타 난 횟수 는 2000 회 (2 * 103, 그 중에서 2 의 첫 번 째 수 치 였 다. 103 은 숫자의 뒷 네 자리 숫자 중 한 자리 가 1 이 고 나머지 세 자리 숫자 는 0 에서 9 까지 10 개의 숫자 를 임의로 선택 할 수 있 으 며 배열 조합 으로 총 횟수 는 2 * 103) 임 을 알 수 있 기 때문이다.
1 부터 1345 까지 의 모든 숫자 중 1 이 나타 난 횟수 에 대해 우 리 는 재 귀적 으로 구 할 수 있다.이것 도 우리 가 왜 1 - 21345 를 1 - 1235 와 1346 - 21345 두 단락 으로 나 누 어야 하 는 이유 이다.21345 의 최고 위 치 를 없 애 면 1345 를 얻 을 수 있 기 때문에 우 리 는 재 귀 적 인 사 고 를 사용 하 는 데 편리 하 다.
여기 서 또 하나의 특수 한 상황 을 분석 할 때 주의해 야 한다. 앞에서 우리 가 예 를 들 면 가장 높 은 자 리 는 1 보다 큰 숫자 이 고 이때 가장 높 은 자리 1 이 나타 난 횟수 는 104 (다섯 자리 수 에 대해 말하자면) 이다.그런데 최고 자리 가 1 이 라면?예 를 들 어 12345 를 입력 하면 10000 에서 12345 까지 이 숫자 들 중에서 1 만 자리 에서 나타 나 는 횟수 는 104 번 이 아니 라 2346 번 이다. 즉, 가장 높 은 숫자 를 제외 한 나머지 숫자 에 1 을 더 하 는 것 이다.
앞의 분석 을 바탕 으로 우 리 는 다음 과 같은 코드 를 쓸 수 있다.참고 코드 에서 프로 그래 밍 이 편리 하도록 나 는 숫자 를 문자열 로 바 꾸 었 다.
#include <iostream>
#include "string.h"
#include "stdlib.h"
#include <stdio.h>
using namespace std;
int NumberOf1(const char* strN);
int PowerBase10(unsigned int n);
/////////////////////////////////////////////////////////////////////////////
// Find the number of 1 in an integer with radix 10
// Input: n - an integer
// Output: the number of 1 in n with radix
/////////////////////////////////////////////////////////////////////////////
int NumberOf1BeforeBetween1AndN_Solution2(int n)
{
if(n <= 0)
return 0;
// convert the integer into a string
char strN[50];
sprintf(strN, "%d", n);
return NumberOf1(strN);
}
/////////////////////////////////////////////////////////////////////////////
// Find the number of 1 in an integer with radix 10
// Input: strN - a string, which represents an integer
// Output: the number of 1 in n with radix
/////////////////////////////////////////////////////////////////////////////
int NumberOf1(const char* strN)
{
if(!strN || *strN < '0' || *strN > '9' || *strN == '\0')
return 0;
int firstDigit = *strN - '0';
unsigned int length = static_cast<unsigned int>(strlen(strN));
// the integer contains only one digit
if(length == 1 && firstDigit == 0)
return 0;
if(length == 1 && firstDigit > 0)
return 1;
// suppose the integer is 21345
// numFirstDigit is the number of 1 of 10000-19999 due to the first digit
int numFirstDigit = 0;
// numOtherDigits is the number of 1 01346-21345 due to all digits
// except the first one
int numOtherDigits = firstDigit * (length - 1) * PowerBase10(length - 2);
// numRecursive is the number of 1 of integer 1345
int numRecursive = NumberOf1(strN + 1);
// if the first digit is greater than 1, suppose in integer 21345
// number of 1 due to the first digit is 10^4. It's 10000-19999
if(firstDigit > 1)
numFirstDigit = PowerBase10(length - 1);
// if the first digit equals to 1, suppose in integer 12345
// number of 1 due to the first digit is 2346. It's 10000-12345
else if(firstDigit == 1)
numFirstDigit = atoi(strN + 1) + 1;
return numFirstDigit + numOtherDigits + numRecursive;
}
/////////////////////////////////////////////////////////////////////////////
// Calculate 10^n
/////////////////////////////////////////////////////////////////////////////
int PowerBase10(unsigned int n)
{
int result = 1;
for(unsigned int i = 0; i < n; ++ i)
result *= 10;
return result;
}
int main()
{
int num = NumberOf1BeforeBetween1AndN_Solution2(112452);
cout<<num<<endl;
}
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
다양한 언어의 JSONJSON은 Javascript 표기법을 사용하여 데이터 구조를 레이아웃하는 데이터 형식입니다. 그러나 Javascript가 코드에서 이러한 구조를 나타낼 수 있는 유일한 언어는 아닙니다. 저는 일반적으로 '객체'{}...
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.