面试题10输入一个十进制整数,统计其中二进制1的个数


https://blog.csdn.net/u010425776/article/details/50836554

  1. /**
  2. * 题目:输入一个十进制整数,统计其中二进制1的个数
  3. * @author 大闲人柴毛毛
  4. */
  5. public class CountBitOne {
  6. /**
  7. * 这个问题最直观的思路:
  8. * 将输入的整数转换成二进制数,
  9. * 再把这个二进制数转换成字符数组,
  10. * 最后遍历数组,统计1的个数。
  11. *
  12. * 使用数组需要开辟额外的内存空间,
  13. * 若在不能使用Java相关类库的情况下,
  14. * 要实现十进制向二进制数组的转化实属不易。
  15. * 且该方法需要完整遍历数组,因此需要n次比较。
  16. *
  17. * 下面我们探求更高效的方法。
  18. */
  19. /**
  20. * 这道题涉及到二进制,因此我们应当敏锐地察觉到使用位运算来解决问题!
  21. *
  22. * 位运算具有如下特性:
  23. * 1与一个二进制数进行与运算,若最低位是1,则运算的结果为1,否则结果为0。
  24. *
  25. * 因此,让输入的数与1进行与运算,每运算一次便统计当前结果是否为1,并将数右移一位,
  26. * 当该数为0时统计结束。
  27. *
  28. * 代码实现如下:
  29. */
  30. public static int countBitOne_1(int n){
  31. //n中1的个数
  32. int count = 0;
  33. while(n!= 0){
  34. //判断当前运算结果是否为1
  35. if((n& 1)== 1)
  36. count++;
  37. //将n右移一位
  38. n = n >> 1;
  39. }
  40. return count;
  41. }
  42. /**
  43. * 上述方法有个严重的bug!
  44. * 若一个正数右移n位,则需要用n个1来补齐最高位。
  45. * 因此,当一个正数右移了若干次之后,它的所有位置都被1取代,
  46. * 此时与1进行与运算的结果永远是1,从而出现了死循环。
  47. *
  48. * 如何解决呢?
  49. *
  50. * 出现上述情况的原因有两个:1.右移、2.正数,
  51. * 只要破坏了这两个条件中的任何一个,就能避免死循环的现象。
  52. * 由于本题的输入要求中包含了正整数,因此我们只能破坏第一个条件。
  53. *
  54. * 虽然右移与正负有关,但左移与正负无关!
  55. * 并且要达到和方法1一样的效果,我们就让“00000001”这个序列左移。
  56. *
  57. * 代码如下:
  58. */
  59. public static int countBitOne_2(int n){
  60. //n中1的个数
  61. int count = 0;
  62. //进行左移的序列00000001
  63. int flag = 1;
  64. //当flag不为0的时候循环
  65. while(flag!= 0){
  66. //若当前与运算结果不为0,则表示n当前位置是1
  67. if((n&flag) != 0)
  68. count++;
  69. //flag左移一位
  70. flag = flag << 1;
  71. }
  72. return count;
  73. }
  74. /**
  75. * 这种方式不需要额外的内存空间,
  76. * 而且十进制位运算的过程中,进制的转化由JVM完成,无需程序猿手动实现。
  77. * 这种方法的时间复杂度为O(n),需要进行n次比较。
  78. *
  79. * 下面介绍更高效的方式。
  80. */
  81. /**
  82. * 如果将一个二进制数-1,那么该二进制数最右侧的1将会变成0,1后面的0均变成1,1前面的数保持不变。
  83. * 也就是说,如果一个二进制数-1,那么该数最右侧的1及1右侧的所有数均变成相反数。
  84. * 如果把这个数和原数与运算,那么最右侧的那个1前面的数将不变,1及1右侧的所有数均变为0。
  85. * 也就是说,进行一次上述的运算后,原数最右侧的那个1将会变成0,
  86. * 那么只要重复上述操作,当原数变成0时,循环的次数就是1的个数。
  87. *
  88. * 代码如下:
  89. */
  90. public static int countBitOne_3(int n){
  91. //n中1的个数
  92. int count = 0;
  93. while(n!= 0){
  94. n = n & (n- 1);
  95. count++;
  96. }
  97. return count;
  98. }
  99. }

  1. /**
  2. * 题目:输入一个十进制整数,统计其中二进制1的个数
  3. * @author 大闲人柴毛毛
  4. */
  5. public class CountBitOne {
  6. /**
  7. * 这个问题最直观的思路:
  8. * 将输入的整数转换成二进制数,
  9. * 再把这个二进制数转换成字符数组,
  10. * 最后遍历数组,统计1的个数。
  11. *
  12. * 使用数组需要开辟额外的内存空间,
  13. * 若在不能使用Java相关类库的情况下,
  14. * 要实现十进制向二进制数组的转化实属不易。
  15. * 且该方法需要完整遍历数组,因此需要n次比较。
  16. *
  17. * 下面我们探求更高效的方法。
  18. */
  19. /**
  20. * 这道题涉及到二进制,因此我们应当敏锐地察觉到使用位运算来解决问题!
  21. *
  22. * 位运算具有如下特性:
  23. * 1与一个二进制数进行与运算,若最低位是1,则运算的结果为1,否则结果为0。
  24. *
  25. * 因此,让输入的数与1进行与运算,每运算一次便统计当前结果是否为1,并将数右移一位,
  26. * 当该数为0时统计结束。
  27. *
  28. * 代码实现如下:
  29. */
  30. public static int countBitOne_1(int n){
  31. //n中1的个数
  32. int count = 0;
  33. while(n!= 0){
  34. //判断当前运算结果是否为1
  35. if((n& 1)== 1)
  36. count++;
  37. //将n右移一位
  38. n = n >> 1;
  39. }
  40. return count;
  41. }
  42. /**
  43. * 上述方法有个严重的bug!
  44. * 若一个正数右移n位,则需要用n个1来补齐最高位。
  45. * 因此,当一个正数右移了若干次之后,它的所有位置都被1取代,
  46. * 此时与1进行与运算的结果永远是1,从而出现了死循环。
  47. *
  48. * 如何解决呢?
  49. *
  50. * 出现上述情况的原因有两个:1.右移、2.正数,
  51. * 只要破坏了这两个条件中的任何一个,就能避免死循环的现象。
  52. * 由于本题的输入要求中包含了正整数,因此我们只能破坏第一个条件。
  53. *
  54. * 虽然右移与正负有关,但左移与正负无关!
  55. * 并且要达到和方法1一样的效果,我们就让“00000001”这个序列左移。
  56. *
  57. * 代码如下:
  58. */
  59. public static int countBitOne_2(int n){
  60. //n中1的个数
  61. int count = 0;
  62. //进行左移的序列00000001
  63. int flag = 1;
  64. //当flag不为0的时候循环
  65. while(flag!= 0){
  66. //若当前与运算结果不为0,则表示n当前位置是1
  67. if((n&flag) != 0)
  68. count++;
  69. //flag左移一位
  70. flag = flag << 1;
  71. }
  72. return count;
  73. }
  74. /**
  75. * 这种方式不需要额外的内存空间,
  76. * 而且十进制位运算的过程中,进制的转化由JVM完成,无需程序猿手动实现。
  77. * 这种方法的时间复杂度为O(n),需要进行n次比较。
  78. *
  79. * 下面介绍更高效的方式。
  80. */
  81. /**
  82. * 如果将一个二进制数-1,那么该二进制数最右侧的1将会变成0,1后面的0均变成1,1前面的数保持不变。
  83. * 也就是说,如果一个二进制数-1,那么该数最右侧的1及1右侧的所有数均变成相反数。
  84. * 如果把这个数和原数与运算,那么最右侧的那个1前面的数将不变,1及1右侧的所有数均变为0。
  85. * 也就是说,进行一次上述的运算后,原数最右侧的那个1将会变成0,
  86. * 那么只要重复上述操作,当原数变成0时,循环的次数就是1的个数。
  87. *
  88. * 代码如下:
  89. */
  90. public static int countBitOne_3(int n){
  91. //n中1的个数
  92. int count = 0;
  93. while(n!= 0){
  94. n = n & (n- 1);
  95. count++;
  96. }
  97. return count;
  98. }
  99. }

猜你喜欢

转载自blog.csdn.net/qq_20398345/article/details/80879219