面试问题:
创建一个输入'N'(无符号长)并打印两列的程序,第一列打印从1到N的数字(十六进制格式),第二列打印二进制表示中的1的数量左栏中的数字。条件是这个程序不应该计算1s(所以没有计算'每个数''得到1s /没有除法运算符。)
我试图通过利用这样的事实来实现这一点:0x0到0xF中的1号可以重新用于为任何数字生成1。我粘贴代码(基本的没有错误检查。)它给出了正确的结果,但我对空间使用不满意。我该如何改进呢? (我也不确定面试官是在寻找什么)。
void printRangeFasterWay(){
uint64_t num = ~0x0 ;
cout << " Enter upper number " ;
cin >> num ;
uint8_t arrayCount[] = { 0,1,1,2,1,2,2,3,1,2,2,3,2,3,3,4} ;
// This array will store information needed to print
uint8_t * newCount = new uint8_t[num] ;
uint64_t mask = 0x0 ;
memcpy(newCount, &arrayCount[0], 0x10) ;
uint64_t lower = 0;
uint64_t upper = 0xF;
uint64_t count = 0 ;
uint32_t zcount= 0 ;
do{
upper = std::min(upper, num) ;
for(count = lower ; count <= upper ; count++){
newCount[count] = (uint32_t)( newCount[count & mask] + newCount[(count & ~mask)>>(4*zcount)]) ;
}
lower += count ;
upper |= (upper<<4) ;
mask = ((mask<<4) | 0xF ) ;
zcount++ ;
}while(count<=num) ;
for(uint64_t xcount=0 ; xcount <= num ; xcount++){
cout << std::hex << " num = " << xcount << std::dec << " number of 1s = " << (uint32_t)newCount[xcount] << endl;
}
}
Enter upper number 18
num = 0 number of 1s = 0
num = 1 number of 1s = 1
num = 2 number of 1s = 1
num = 3 number of 1s = 2
num = 4 number of 1s = 1
num = 5 number of 1s = 2
num = 6 number of 1s = 2
num = 7 number of 1s = 3
num = 8 number of 1s = 1
num = 9 number of 1s = 2
num = a number of 1s = 2
num = b number of 1s = 3
num = c number of 1s = 2
num = d number of 1s = 3
num = e number of 1s = 3
num = f number of 1s = 4
num = 10 number of 1s = 1
num = 11 number of 1s = 2
num = 12 number of 1s = 2
答案 0 :(得分:5)
我有一个稍微不同的方法,可以解决你的记忆问题。它基于以下事实:按位运算i & -i
为您提供数字i
中最小的2的幂。例如,i = 5
,i & -i = 1
,i = 6
,i & -i = 2
。现在,代码:
void countBits(unsigned N) {
for (int i = 0;i < N; i ++)
{
int bits = 0;
for (int j = i; j > 0; j= j - (j&-j))
bits++;
cout <<"Num: "<<i <<" Bits:"<<bits<<endl;
}
}
我希望我能正确理解你的问题。希望有所帮助
修改强> 好吧,试试这个 - 这是动态编程而不使用每个数字中的每一位:
void countBits(unsigned N) {
unsigned *arr = new unsigned[N + 1];
arr[0]=0;
for (int i = 1;i <=N; i ++)
{
arr[i] = arr[i - (i&-i)] + 1;
}
for(int i = 0; i <=N; i++)
cout<<"Num: "<<i<<" Bits:"<<arr[i]<<endl;
}
希望这更好用
答案 1 :(得分:2)
到目前为止发布的几个答案都使用了位移(只有另一个词除以2)或 比特掩蔽。这让我觉得有点作弊。同样,以4位模式使用“1”位计数 通过4比特的块进行匹配。
使用虚构二进制树的简单递归解决方案怎么样?每个左分支包含一个'0',每个 右分支包含'1'。然后进行深度优先遍历,计算向下的1位数。一旦 到达树的底部,向计数器添加一个,打印出目前为止找到的1位数,然后退出 一级并再次递归。
当计数器达到所需的数字时停止递归。
我不是C / C ++程序员,但这里是一个REXX解决方案,应该没有太多想象力。注意 幻数32只是无符号长的位数。将其设置为任何内容
/* REXX */
SAY 'Stopping number:'
pull StopNum
Counter = 0
CALL CountOneBits 0, 0
return
CountOneBits: PROCEDURE EXPOSE Counter StopNum
ARG Depth, OneBits
If Depth = 32 then Return /* Number of bits in ULong */
if Counter = StopNum then return /* Counted as high as requested */
call BitCounter Depth + 1, OneBits /* Left branch is a 0 bit */
call BitCounter Depth + 1, OneBits + 1 /* Right branch is a 1 bit */
Return
BitCounter: PROCEDURE EXPOSE Counter StopNum
ARG Depth, OneBits
if Depth = 32 then do /* Bottom of binary bit tree */
say D2X(Counter) 'contains' OneBits 'one bits'
Counter = Counter + 1
end
call CountOneBits Depth, OneBits
return
结果:
Stopping number:
18
0 contains 0 one bits
1 contains 1 one bits
2 contains 1 one bits
3 contains 2 one bits
4 contains 1 one bits
5 contains 2 one bits
6 contains 2 one bits
7 contains 3 one bits
8 contains 1 one bits
9 contains 2 one bits
A contains 2 one bits
B contains 3 one bits
C contains 2 one bits
D contains 3 one bits
E contains 3 one bits
F contains 4 one bits
10 contains 1 one bits
11 contains 2 one bits
这个答案在时间和空间上都是合理有效的。
答案 2 :(得分:1)
通过适当的位切换,可以在恒定时间内相对简单地完成。不计1分,不分。我认为你在保持已知位值数组的正确轨道上:
int bits(int x)
{
// known bit values for 0-15
static int bc[16] = {0,1,1,2,1,2,2,3,1,2,2,3,2,3,3,4};
// bit "counter"
int b = 0;
// loop iterator
int c = 0;
do
{
// get the last 4 bits in the number
char lowc = static_cast<char>(x & 0x0000000f);
// find the count
b += bc[lowc];
// lose the last four bits
x >>= 4;
++c;
// loop for each possible 4 bit combination,
// or until x is 0 (all significant bits lost)
}
while(c < 8 && x > 0);
return b;
}
答案 3 :(得分:0)
以下算法与您的算法相似,但扩展了这个想法(如果我理解您的方法正确的话。)它不按照问题的指示进行任何“每个数字”的计算,而是使用在序列之间存在的递归长度为2的幂。基本上,观察结果是对于序列0, 1,..,2^n-1
,我们可以按以下方式使用序列0, 1, ...,2^(n-1)-1
。
对于所有f(i)
,i
为f(2^(n-1)+i)=f(i)+1
的数量,然后是0<=i<2^(n-1)
。 (自己验证)
#include <stdio.h>
#include <stdlib.h>
int main( int argc, char *argv[] )
{
const int N = 32;
int* arr = new int[N];
arr[0]=0;
arr[1]=1;
for ( int i = 1; i < 15; i++ )
{
int pow2 = 1 << i;
int offset = pow2;
for ( int k = 0; k < pow2; k++ )
{
if ( offset+k >= N )
goto leave;
arr[offset+k]=arr[k]+1;
}
}
leave:
for ( int i = 0; i < N; i++ )
{
printf( "0x%8x %16d", i, arr[i] );
}
delete[] arr;
return EXIT_SUCCESS;
}
请注意,在for循环中
for ( int i = 0; i < 15; i++ )
如果你的数字高于15,可能会出现负数溢出,否则如果你想要高于15,则使用unsigned int。
此算法在O(N)
中运行,并使用O(N)
空格。
答案 4 :(得分:0)
这是一种具有O(nlogn)时间复杂度和O(1)内存使用的方法。我们的想法是获得Hex的等价数字并迭代它以获得每个Hex数字的数量。
int oneCount[] = { 0,1,1,2,1,2,2,3,1,2,2,3,2,3,3,4};
int getOneCount(int n)
{
char inStr[70];
sprintf(inStr,"%X",n);
int i;
int sum=0;
for(i=0; inStr[i];i++)
{
if ( inStr[i] > '9' )
sum += oneCount[inStr[i]-'A' + 10];
else
sum+= oneCount[inStr[i] -'0'];
}
return sum;
}
int i,upperLimit;
cin>>upperLimit;
for(i=0;i<=upperLimit;i++)
{
cout << std::hex << " num = " << i << std::dec << " number of 1s = " << getOneCount(i) << endl;
}
答案 5 :(得分:0)
enum bit_count_masks32
{
one_bits= 0x55555555, // 01...
two_bits= 0x33333333, // 0011...
four_bits= 0x0f0f0f0f, // 00001111....
eight_bits= 0x00ff00ff, // 0000000011111111...
sixteen_bits= 0x0000ffff, // 00000000000000001111111111111111
};
unsigned int popcount32(unsigned int x)
{
unsigned int result= x;
result= (result & one_bits) + (result & (one_bits << 1)) >> 1;
result= (result & two_bits) + (result & (two_bits << 2)) >> 2;
result= (result & four_bits) + (result & (four_bits << 4)) >> 4;
result= (result & eight_bits) + (result & (eight_bits << 8)) >> 8;
result= (result & sixteen_bits) + (result & (sixteen_bits << 16)) >> 16;
return result;
}
void print_range(unsigned int low, unsigned int high)
{
for (unsigned int n= low; unsigned int n<=high; ++n)
{
cout << std::hex << " num = " << xcount << std::dec << " number of 1s = " << popcount32(n) << endl;
}
}