leetcode-338-比特位计数-java

题目及测试

package pid338;
/* 338. 比特位计数

给定一个非负整数 num。对于 0 ≤ i ≤ num 范围中的每个数字 i ,计算其二进制数中的 1 的数目并将它们作为数组返回。

示例 1:

输入: 2
输出: [0,1,1]  0  01  10

示例 2:

输入: 5
输出: [0,1,1,2,1,2]  0  01  10  11       100  101  110  111

进阶:

    给出时间复杂度为O(n*sizeof(integer))的解答非常容易。但你可以在线性时间O(n)内用一趟扫描做到吗?
    要求算法的空间复杂度为O(n)。
    你能进一步完善解法吗?要求在C++或任何其他语言中不使用任何内置函数(如 C++ 中的 __builtin_popcount)来执行此操作。



*/
public class main {
	
	public static void main(String[] args) {
		int[] testTable = {2,5};
		for (int i=0;i<testTable.length;i++) {
			test(testTable[i]);
		}
	}
		 
	private static void test(int ito) {
		Solution solution = new Solution();
		int[] rtn;
		long begin = System.currentTimeMillis();
		    System.out.print(ito+" ");
		    System.out.println();
		rtn = solution.countBits(ito);//执行程序
		long end = System.currentTimeMillis();		
		System.out.println("rtn=" );
		for (int i = 0; i < rtn.length; i++) {
		    System.out.print(rtn[i]+" ");
		}//打印结果几数组
		System.out.println();
		System.out.println("耗时:" + (end - begin) + "ms");
		System.out.println("-------------------");
	}

}

解法1(成功,2ms,较快)

可以看0-1与2-3

00  01 

10  11 

可以看到2-3就是在0-1的前面加了个1,所以num[2]=num[0]+1,num[3]=num[1]+1

000  001  010  011       100  101  110  111

可以看到4-7同样也是比0-3每个都多了一个1

可以认为num[i]=num[i-size]+1  size为刚刚小于等于i的2^n

这种方法实际是动态规划 + 最高有效位(与其他结果的最高有效位不同)

package pid338;

class Solution {
    public int[] countBits(int num) {
    	if(num == 0){
    		return new int[]{0};
    	}
    	if(num == 1){
    		return new int[]{0,1};
    	}
    	if(num == 2){
    		return new int[]{0,1,1};
    	}
    	if(num == 3){
    		return new int[]{0,1,1,2};
    	}
    	// 处理>=4的情况
    	int[] result = new int[num+1];
    	result[0] = 0;
    	result[1] = 1;
    	result[2] = 1;
    	result[3] = 2;
    	int size = 4;
    	for(int i=4;i<=num;i++){
    		result[i] = result[i-size]+1;
    		if(i == size * 2 - 1){
    			size = size * 2;
    		}
    	}
    	return result;
    }
}

解法2(别人的)

遵循上一方法的相同原则,我们还可以通过最低有效位来获得状态转移函数。

观察x 和 x′=x/2 的关系:

x=(1001011101)2=(605)10

x′=(100101110)2=(302)10

可以发现 x′ 与 x 只有一位不同,这是因为x′ 可以看做 x 移除最低有效位的结果。

这样,我们就有了下面的状态转移函数:

P(x)=P(x/2)+(xmod 2)

public class Solution {
  public int[] countBits(int num) {
      int[] ans = new int[num + 1];
      for (int i = 1; i <= num; ++i)
        ans[i] = ans[i >> 1] + (i & 1); // x / 2 is x >> 1 and x % 2 is x & 1
      return ans;
  }
}

解法3(别人的)

动态规划 + 最后设置位

与上述方法思路相同,我们可以利用最后设置位。

最后设置位是从右到左第一个为1的位。使用 x &= x - 1 将该位设置为0,就可以得到以下状态转移函数:

P(x)=P(x&(x−1))+1;

public class Solution {
  public int[] countBits(int num) {
      int[] ans = new int[num + 1];
      for (int i = 1; i <= num; ++i)
        ans[i] = ans[i & (i - 1)] + 1;
      return ans;
  }
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值