EPI_PrimitiveTypes_No.001_ParityOfAWord

关于EPI

EPI即Elements Programming Interviews这本书,是除了CC189以外我见过最好的讲面试的书。
这本书的风格和CC189还不是完全一样,三个作者都是男性,也都是资深的软件工程师,不少分析的角度都非常独到而严谨。

问题描述

给定一个64位整型数,求其Parity,即1的个数如果是奇数,Parity=1,否则Parity=0.

思路解析

这道题要做出来不难,但可以深挖出不少做法,也算是有一定代表性。

  1. 暴力破解
    所谓暴力破解,那就是1位1位地试,然后用一个数来存1的个数。这样做的话时间复杂度是O(n),n是数字的2进制有效位数。
public static short parity(long x) {
        short result = 0;
        while (x != 0) {
            result ^= (x & 1);
            x >>>= 1;
        }
        return result;
}
  1. 稍微改进一点的解法
    上面一种解法,假如只是最高位有1个1,也要数遍所有位数。所以,改进一下,每次解决1个1,那么假如有s个1,复杂度就是O(s):
public static short parity(long x) {
        short result = 0;
        while (x != 0) {
            result ^= 1;
            x &= (x - 1); // Drops the lowest set bit of x.
        }
        return result;
}
  1. 思维飞跃:使用哈希表
    前面两种方法都是要遍历二进制数,所以复杂度是线性的。
    在此前提下,如何提高时间效率?有一种常见的方法就是空间换时间,也就是说事先算好的结果存起来,到时候直接查表。
    那么,也就是说假如可以把64位Parity所有可能的情况都存起来,那么查表的时间复杂度就是O(1)。
    当然,这样需要太大空间。可以适当削减一下,比如只保存16位整数的Parity,那么64位分成4个16位然后分别查表组合起来就行:
public static short parity(long x) {
        final int WORD_SIZE = 16;
        final int BIT_MASK = 0xFFFF ;
        return (short) (
        precomputedParity[(int)((x >>> (3 * WORD_SIZE)) & BIT_MASK)]
      ^ precomputedParity[(int)((x >>> (2 * WORD_SIZE)) & BIT_MASK)]
      ^ precomputedParity[(int)((x >>> WORD_SIZE) & BIT_MASK)]
      ^ precomputedParity[(int)(x & BIT_MASK)]);
}

不失一般性,设word_size为L,那么时间复杂度就是O(n/L)。

  1. 思维再飞跃:使用Parity特性
    在上面一种解法中,我们使用异或将不同部分的结果组合起来。道理也很简单,稍微思考一下就能明白。而利用这个特性,有一种O(logn)且不借助哈希表的解法,就是不断地折半异或:
public static short parity(long x) {
    x ^= x >>> 32;
    x ^= x >>> 16;
    x ^= x >>> 8;
    x ^= x >>> 4;
    x ^= x >>> 2;
    x ^= x >>> 1;
    return (short) (x & 0x1);
}

总结

恢复刷题,因此选择一个不是很难的问题。但同时这道题里面也蕴含着许多位操作的相关手段,例如如何抽离最低位的1,Hashmap对位运算的价值,等等。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

  • 背景 一年多以前我在知乎上答了有关LeetCode的问题, 分享了一些自己做题目的经验。 张土汪:刷leetcod...
    土汪阅读 12,793评论 0 33
  • 串口操作 串口操作需要的头文件 #include /*标准输入输出定义*/ #include /*标准函数库定...
    旅行家John阅读 1,424评论 0 3
  • 夕阳 趴在西山的背上 怀想 月亮 躲在夜色的幕后 化妆 拐杖 推起破旧的轮椅 登场
    一杯老酒阅读 224评论 2 1
  • 已经是春末夏初了,一连好几个星期的蓝天白云,让人掉以轻心地认为霾将消失很长一段时间,可以好好享受一阵子舒心...
    汉方清荷阅读 382评论 0 0
  • 昨天中午一个人去电影院看了《二十二》,在晚上的时候又看了《三十二》。最早知道这个“慰安妇”这个名词,是在高中的时候...
    米小王子阅读 350评论 0 3