【第一题】丢失的数字
分析:
1.位运算异或。
2.求和。由1到n项的数列和-目前的sum
3.哈希表/桶
//1.位运算异或。
//执行用时:0 ms, 在所有 Java 提交中击败了100.00% 的用户
//内存消耗:38.9 MB, 在所有 Java 提交中击败了63.68% 的用户
class Solution{
public int missingNumber(int[] nums){
int res = nums.length;
for(int i = 0;i < nums.length;i++){
res ^= nums[i] ^i;
}
return res;
}
}
//执行用时:0 ms, 在所有 Java 提交中击败了100.00% 的用户
//内存消耗:39.1 MB, 在所有 Java 提交中击败了36.75% 的用户
class Solution {
public int missingNumber(int[] nums) {
int sum = 0;
for(int i = 0;i < nums.length;i++){
sum += nums[i];
}
return nums.length *(nums.length + 1)/2-sum;
}
}
【第二题】数字转换为十六进制数
分析:
//执行用时:0 ms, 在所有 Java 提交中击败了100.00% 的用户
//内存消耗:35.7 MB, 在所有 Java 提交中击败了52.89% 的用户
class Solution {
public String toHex(int num) {
if(num == 0){return "0";}
char[] chars = {'0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f'};
StringBuilder sb = new StringBuilder();
while(sb.length() < 8 && num!=0){
sb.append(chars[num & 0xf]);
num >>=4;
}
return sb.reverse().toString();
}
}
【第三题】2的幂
分析:
方法一:n&n-1 == 0?
方法二:n & -n == n?
//执行用时:1 ms, 在所有 Java 提交中击败了100.00% 的用户
//内存消耗:35.4 MB, 在所有 Java 提交中击败了80.26% 的用户
class Solution {
public boolean isPowerOfTwo(int n) {
if(n <=0) return false;
if((n & n-1) == 0){
return true;
}
return false;
}
}
//执行用时:1 ms, 在所有 Java 提交中击败了100.00% 的用户
//内存消耗:35.3 MB, 在所有 Java 提交中击败了89.05% 的用户
class Solution {
public boolean isPowerOfTwo(int n) {
return (n > 0) && (n & -n);
}
}
【第四题】插入
分析:首先构造二进制位,根据需要插入的起始位和终止位,(也就是说,把起始位到终止位的部分都设置成0,其他的都是1),然后N=N&n,目的是使N的i-j位全部为0,便于下一步的插入。然后把M左移i位,这样末尾就是第i-j位,最后把M和N进行或运算,得出结果。
class Solution{
public static insertBits(int N,int N,int i,int j){
int n = ~((-1 >>>(31-j))&(-1<<i));
N = N&n;
M = M<<i;
N=M|N;
return N;
}
}
//执行用时:0 ms, 在所有 Java 提交中击败了100.00% 的用户
//内存消耗:35.3 MB, 在所有 Java 提交中击败了43.37% 的用户
class Solution {
public int insertBits(int N, int M, int i, int j) {
int mask = ~(((1 << (j-i+1))-1) << i);
N&=mask;
M = M<<i;
return M|N;
}
}
【第四题】两整数之和
分析:两个整数a,b。假如没有进位,那么a^b就是两者之和;假如有进位,让无进位相加的结果与进位不断地异或,直到进位为0.
//执行用时:0 ms, 在所有 Java 提交中击败了100.00% 的用户
//内存消耗:35.4 MB, 在所有 Java 提交中击败了24.37% 的用户
class Solution {
public int getSum(int a, int b) {
int sum,carry;
sum = a^b;
carry = (a & b) <<1;
if(carry !=0){
return getSum(sum,carry);
}
return sum;
}
}
【第五题】位1的个数
分析:
方法一:移位操作,假如末尾是1,count++,然后算术右移(不考虑符号位)。
方法二:
//执行用时:1 ms, 在所有 Java 提交中击败了95.41% 的用户
//内存消耗:35.3 MB, 在所有 Java 提交中击败了68.12% 的用户
public class Solution {
// you need to treat n as an unsigned value
public int hammingWeight(int n) {
int cnt = 0;
while(n !=0){
n &= (n-1);
cnt++;
}
return cnt;
}
}
【第六题】二进制手表(挖坑等回溯算法)
https://leetcode-cn.com/problems/binary-watch/
分析:二进制手表第一排的四个灯表示(0-11),第二排的6个灯表示分钟(0-59),都是根据二进制位,亮灯为1,不亮为0.
给定亮灯数目,返回所有可能的时间。其实就是判断1的个数
要注意的是小时和分钟的格式,小时(是几位就是几位),分钟(一律两位数,不足两位高位补零)。
【第七题】多数元素
分析:这个题可以分成两道题做。
方法一:排序+双指针;
方法二:直接排序求中位数;
方法三:位运算(假如该数为众数,那么出现该数的次数一定大于n/2,同理它的二进制位上每个1的个数也大于n/2,只要统计每一位1出现的次数大于n/2的相加得出结果即可。假如出现最多次数的是0,那么没有一个数出现的1大于n/2,直接返回0即可);
方法四:哈希表(杀鸡用牛刀的意思)
方法五:投票法(假如只有两种元素,那么可以直接用flag消除法。多种元素和消除法一样的思路,投票法,最后剩下的那个数一定是众数)
//执行用时:3 ms, 在所有 Java 提交中击败了43.19% 的用户
//内存消耗:41.7 MB, 在所有 Java 提交中击败了66.36% 的用户
class Solution {
public int majorityElement(int[] nums) {
if(nums.length == 1 || nums.length == 2){return nums[0];}
// if(nums.length == 2){
// // if(nums[0] == nums[1]){
// // return nums[0];
// // }else{
// // return 0;
// // }
// return nums[0];
// }
Arrays.sort(nums);
int count = 1;
int i = 0,j = 1;
while(j < nums.length){
if(nums[j] == nums[i]){
count++;
j++;
}else{
if(count > nums.length/2){
return nums[i];
}else{
i = j;
j++;
}
}
}
return count > nums.length/2? nums[i]:0;
}
}
//执行用时:2 ms, 在所有 Java 提交中击败了74.14% 的用户
//内存消耗:41.6 MB, 在所有 Java 提交中击败了80.18% 的用户
class Solution {
public int majorityElement(int[] nums) {
if(nums.length == 1 || nums.length == 2){return nums[0];}
Arrays.sort(nums);
return nums[nums.length/2];
}
}
class Solution{
public int majorityElement(int[] nums) {
int result = 0, k = nums.length >> 1;
for (int j = 0; j < 32; j++) {
int count = 0;
for (int num : nums) {
count += num >> j & 1;
if (count > k) {
result += 1 << j;
break;
}
}
}
return result;
}
}
//执行用时:3 ms, 在所有 Java 提交中击败了43.19% 的用户
//内存消耗:44.4 MB, 在所有 Java 提交中击败了5.03% 的用户
class Solution{
public int majorityElement(int[] nums){
int count = 0;
Integer candidate = null;
for(int num:nums){
if(count == 0){candidate = num;}
count+=(num == candidate)?1:-1;
}
return candidate;
}
}
【第八题】二进制表示中质数个计算置位
分析:简简单单统计个数,简简单单判断质数。不是吧,看完官方题解表示还能这么搞?
//执行用时:41 ms, 在所有 Java 提交中击败了18.66% 的用户
//内存消耗:35.2 MB, 在所有 Java 提交中击败了77.65% 的用户
class Solution {
public int countPrimeSetBits(int L, int R) {
int cnt = 0;
for(int i = L;i <= R;i++){
if(isPrime(countOne(i))){
cnt++;
}
}
return cnt;
}
public int countOne(int n){
int count = 0;
while(n!=0){
if((n & 1) == 1){
count++;
}
n = n>>>1;
}
return count;
}
public boolean isPrime(int n){
if(n == 1){return false;}
for(int i = 2;i <= Math.sqrt(n);i++){
if(n % i == 0){
return false;
}
}
return true;
}
}
class Solution {
public int countPrimeSetBits(int L, int R) {
int ans = 0;
for (int x = L; x <= R; ++x)
if (isSmallPrime(Integer.bitCount(x)))
ans++;
return ans;
}
public boolean isSmallPrime(int x) {
return (x == 2 || x == 3 || x == 5 || x == 7 ||
x == 11 || x == 13 || x == 17 || x == 19);
}
}
【第九题】配对交换
分析:
//执行用时:0 ms, 在所有 Java 提交中击败了100.00% 的用户
//内存消耗:35.3 MB, 在所有 Java 提交中击败了46.26% 的用户
class Solution {
public int exchangeBits(int num) {
int ans = 0;
for (int i = 0; i < 30; i += 2) {
//取每个奇数位
int a = num & (1 << i);
//取每个偶数位
int b = num & (1 << (i + 1));
//将偶数位设置为a,将奇数位设置为b
ans |= (a << 1);
ans |= (b >> 1);
}
return ans;
}
}
//这个题解太妙了
/*思路的话就是分别取出奇数位和偶数位,移动后做或运算。
题目规定 num 是int范围的数
0x55555555 = 0b0101_0101_0101_0101_0101_0101_0101_0101
0xaaaaaaaa = 0b1010_1010_1010_1010_1010_1010_1010_1010
用这两个数做与运算,就可以把奇数位和偶数位取出来,
然后位左移奇数位,右移偶数位,再把奇数位和偶数位做或运算
作者:releng-xing
链接:https://leetcode-cn.com/problems/exchange-lcci/solution/wei-yun-suan-jie-jue-by-releng-xing/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
*/
class Solution {
public int exchangeBits(int num) {
//奇数
int odd = num & 0x55555555;
//偶数
int even = num & 0xaaaaaaaa;
odd = odd << 1;
even = even >>> 1;
return odd | even;
}
}
【第十题】颠倒二进制位
分析:初始化变量res存放num的位,每次获取num的最后一位,和res相或,然后将num右移,将res左移,循环32次,最后的结果就是res
//执行用时:1 ms, 在所有 Java 提交中击败了99.97% 的用户
//内存消耗:38.3 MB, 在所有 Java 提交中击败了38.97% 的用户
class Solution{
public int reverseBits(int n){
int res = 0;
for(int i = 0;i < 32;++i){
res = res << 1;
res = n&1 | res;
n = n >> 1;
}
return res;
}
}
【第十一题】消失的数字
分析:重拳出击后发现,击败17%。
方法一:排序+数组元素与下标对比
方法二:异或(数字、下标一起异或,假如数字存在,那么必定有和它相同的下标,根据异或的交换律,就有异或结果为0,异或结果就是消失的那个数)
方法三:等差数列求和公式-sum
//执行用时:6 ms, 在所有 Java 提交中击败了17.77% 的用户
//内存消耗:39 MB, 在所有 Java 提交中击败了45.90% 的用户
class Solution {
public int missingNumber(int[] nums) {
Arrays.sort(nums);
for(int i = 0;i < nums.length;i++){
if(i!=nums[i]){
return i;
}
}
return nums.length;
}
}
//执行用时:0 ms, 在所有 Java 提交中击败了100.00% 的用户
//内存消耗:38.8 MB, 在所有 Java 提交中击败了74.32% 的用户
class Solution{
public int missingNumber(int[]nums){
int result=nums.length;
for(int i=0;i<nums.length;i++){
result^=i^nums[i];
}
return result;
}
}
【第十二题】交替位二进制数
分析:
方法一:移位,直接取末尾数比较。
方法二:String str = Integer.toBinaryString(n);对字符串进行操作
//执行用时:0 ms, 在所有 Java 提交中击败了100.00% 的用户
//内存消耗:35.2 MB, 在所有 Java 提交中击败了64.31% 的用户
class Solution {
public boolean hasAlternatingBits(int n) {
while(n!=0){
int num1 = n&1;
n >>=1;
int num2 = n&1;
if(num1 == num2){
return false;
}
}
return true;
}
}
【第十三题】4的幂
分析:除了0以外,假如末尾有偶数个0,且首位为1,就是4的幂。也就是说,只有1个1,且出现在奇数位。
//执行用时:1 ms, 在所有 Java 提交中击败了100.00% 的用户
//内存消耗:35.3 MB, 在所有 Java 提交中击败了85.12% 的用户
class Solution{
public boolean isPowerOfFour(int num){
//检查是不是2的幂
return (num > 0) && ((num & (num-1)) == 0 && (num % 3 == 1));
}
}
//执行用时:1 ms, 在所有 Java 提交中击败了100.00% 的用户
//内存消耗:35.3 MB, 在所有 Java 提交中击败了81.43% 的用户
class Solution {
public boolean isPowerOfFour(int n) {
if(n < 0){return false;}
if(n == 1){return true;}
int temp = n;
int Total = 0;//统计位数
int countZero = 0;//统计0的个数
while(n !=0){
if((n&1) == 0){
countZero++;
}
Total++;
n >>=1;
}
temp = temp >> (Total-1);//保存首位
if(temp == 1 && countZero+1==Total && countZero%2==0){
return true;
}
return false;
}
}
【第十四题】汉明距离
分析:重拳出击!
//执行用时:0 ms, 在所有 Java 提交中击败了100.00% 的用户
//内存消耗:35 MB, 在所有 Java 提交中击败了85.31% 的用户
class Solution {
public int hammingDistance(int x, int y) {
int count = 0;
while(x !=0 || y !=0){
if((x&1)!=(y&1)){
count++;
}
x >>= 1;
y >>= 1;
}
while(x!=0){
x >>=1;
count++;
}
while(y!=0){
y >>=1;
count++;
}
return count;
}
}
【第十六题】翻转数位
分析:题意——将一个数位从0变为1,找出最长的1的长度。
注意负数!注意二进制32位全为1的数!注意注意二进制位是全1,但是不是32个1的数!
//执行用时:0 ms, 在所有 Java 提交中击败了100.00% 的用户
//内存消耗:35 MB, 在所有 Java 提交中击败了93.35% 的用户
class Solution {
public int reverseBits(int num) {
if(num == 0){return 1;}
int maxLen = 0,curLen = 0;
//只允许一次翻转
boolean flag = true;
int num1 = 0;
//记录二进制位总数
int count1 = 0;
//记录1的个数
int count2 = 0;
while(num !=0){
if((num & 1) == 1){
curLen++;
if(flag == false){
num1++;
}
count2++;
}else{
//第一次翻转
if(flag == true){
curLen++;
flag = false;
}else{
//之后遇到0则num1重新计数
maxLen = Math.max(maxLen,curLen);
curLen = num1+1;
num1 = 0;
}
}
//System.out.println(num&1);
num >>>=1;
count1++;
}
if(count1 == count2 && count1 < 32){
curLen++;
}
maxLen = Math.max(maxLen,curLen);
return maxLen;
}
}
【第十七题】最大数值
分析:相减看是负数还是正数(看最高位是否为1)
//执行用时:0 ms, 在所有 Java 提交中击败了100.00% 的用户
//内存消耗:35.3 MB, 在所有 Java 提交中击败了52.85% 的用户
class Solution {
public int maximum(int a, int b) {
long val = (long)a - (long)b;
int[] r = new int[]{a,b};
return r[(int)(val >>> 63)];
}
}
【第十八题】数字的补数
分析:假如输入的数为num,num取反:num ^ (num.length个1)。
//执行用时:0 ms, 在所有 Java 提交中击败了100.00% 的用户
//内存消耗:35.4 MB, 在所有 Java 提交中击败了28.37% 的用户
class Solution {
public int findComplement(int num) {
int temp = num;
int flag = 0;
while(temp!=0){
flag++;
//相当于右移操作
temp /=2;
}
return num^(int)(Math.pow(2,flag) - 1);
}
}
【第十九题】整数转换
分析:其实就是输出两者的二进制位有几个不同——汉明距离。
两者异或之后,看1的个数。每执行一次x = x&(x-1),会将x用二进制表示时最右边的一个1变为0,将所有的1都变为0,这时就统计出了二进制位中1的个数。
//执行用时:0 ms, 在所有 Java 提交中击败了100.00% 的用户
//内存消耗:35.2 MB, 在所有 Java 提交中击败了55.59% 的用户
class Solution {
public int convertInteger(int A, int B) {
int x = A ^ B;
int cnt = 0;
while(x !=0){
x &= (x-1);
cnt++;
}
return cnt;
}
}
【第二十题】不用加号的减法
分析:手动实现进位。
//执行用时:0 ms, 在所有 Java 提交中击败了100.00% 的用户
//内存消耗:35.4 MB, 在所有 Java 提交中击败了31.25% 的用户
class Solution{
public int add(int a,int b){
while(b !=0){
int sum = (a ^ b);
int carry = (a & b) << 1;
//迭代处理
a = sum;
b = carry;
}
return a;
}
}