今天把仙剑三看完了,茂茂割肉让人无法释怀,眼泪止不住的流。长卿和紫萱的分离似乎也意味着重逢,这就是他们的宿命吧。怅然若失的感觉席卷全身,哎,做题吧。
1、题目描述
2、逻辑分析
题目要求将整数从0到此元素(都包括),计算每一个数二进制表示1的个数,返回数组。我想到了那个斐波拉契数,类似阶层,又有所不同,我去看看题解。官方题解给出了四种解法,其中分别是Brian Kernighan 算法与动态规划算法。下面先从第一种方法Brian Kernighan 算法开始。
Brian Kernighan 算法:从0到n,每个整数都分别计算它们的二进制中表示1的个数,再返回数组即可,而使用Brian Kernighan 算法的优点是可以在一定程度上进一步提升计算速度。Brian Kernighan算法的原理是:对于任意整数 x,令 x = x & (x−1),该运算将 x 的二进制表示的最后一个 1 变成 0。因此,对 x 重复该操作,直到 x 变成 0,则操作次数即为 x 的「二进制带有1的比特数」。
3、代码演示
public int [ ] countBits ( int n) { int [ ] bits = new int [ n + 1 ] ; for ( int i = 0 ; i <= n; i++ ) { bits[ i] = countOne ( i) ; } return bits; } public int countOne ( int x) { int ones = 0 ; while ( x > 0 ) { x &= ( x - 1 ) ; ones++ ; } return ones; }
我叫GPT给我写注释,他说我的countOne函数写的不对,问题在于 x &= (x - 1); 这一行。这行代码确实会消除 x 的二进制表示中的最低位的1,但它并不适合用于计数。因为无论你执行多少次这个操作,只要 x 不为0,ones 就会一直增加,即使 x 的某些位原本就是0。应该这样写:
public int countOne ( int x) { int ones = 0 ; while ( x > 0 ) { if ( ( x & 1 ) == 1 ) { ones++ ; } x >>= 1 ; } return ones;
}
时间复杂度:O(nlogn),空间复杂度:O(1)。
接下来一起看看动态规划的解法,我先去看看挑哪一个来写哈!官方的写的太深奥了,我发现了一个天才般的解法:
也就是说,可以根据奇数、偶数中二进制1的个数来解题。下面直接上代码,就像三行情诗一样美哈哈:
public int [ ] countBits ( int n) { int [ ] countOne = new int [ n + 1 ] ; for ( int i = 1 ; i <= n; i++ ) { countOne[ i] = countOne[ i / 2 ] + i % 2 ; } return countOne; }
时间复杂度:O(n),空间复杂度:O(1)。
ok啦,今天差不多就到这儿了,明天好好学习!BYE