《算法之美》学习笔记(一)之位运算

因为要参加蓝桥杯,自己的算法还很弱,就找了个教学视频来看,是郑未的《算法之美》,以此记录一下学习笔记。

位运算

1. 与运算:1&1=1,1&0=0,0&0=0;
2. 或运算:1 | 1 = 1, 1 | 0 = 1, 0 | 0 = 0
3. 异或运算: 1 ^ 1 = 0, 1 ^ 0 = 1, 0 ^ 0 = 0;
3. 左移(<<)除2,右移(>>)乘2;

应用

  1. 判断奇数偶数,将数和1做与运算,结果为1则为奇数,否则为偶数。
  2. 消除重复数,A ^ A ^ B = B 。
  3. n&(n-1)求1的个数

题目

1. 1~N个数,其中有一个数重复,求出该重复数。
思考:在开辟辅助空间的情况下,我们可以开辟一个长度为N的数组然后计数,找出重复数即可。在不开辟辅组空间的情况下,我们可以把1~N和该原数组做^运算,剩下的数即为重复数。
代码:

static int Find(int[] nums) {
  int count = nums[0];
  int j = 1;
  while(j < nums.length) {
   count = count ^ j ^ nums[j];
   j++;
  }
  return count;
 }

leetcode相似题练习:
136. 只出现一次的数字

class Solution {
    public int singleNumber(int[] nums) {
        int count = nums[0];
        for(int i = 1; i < nums.length; i++)
            count = count^nums[i];
        return count;
    } 
}
执行用时 :1 ms, 在所有 Java 提交中击败了99.50% 的用户内存消耗 :39.1 MB

268.缺失数字

class Solution {
    public int missingNumber(int[] nums) {
      int count = nums[0];
        for(int i = 1; i < nums.length;i++){
            count = count ^ i ^ nums[i];
        }
        return count^nums.length;
    }
}
执行用时 :0 ms, 在所有 Java 提交中击败了100.00% 的用户内存消耗 :38.6 MB

389.找不同

class Solution {
    public char findTheDifference(String s, String t) {
         int count = t.charAt(t.length()-1);
         for(int i = 0; i < s.length(); i++) {
             count = count ^ s.charAt(i) ^ t.charAt(i);
         }
         return (char)count;
    }
}
执行用时 :2 ms, 在所有 Java 提交中击败了73.11% 的用户内存消耗 :35.6 MB

287. 寻找重复数

因为不清楚该数出现多少次,也不清楚有那些数出现,所以我没想到怎么位运算。
用了普通的计数:
class Solution {
    public int findDuplicate(int[] nums) {
        int[] arr = new int[nums.length];
        for(int i = 0; i < nums.length; i++) {
                arr[nums[i]] += 1;
                if(arr[nums[i]] > 1)
                    return nums[i];
        }
        return 0;
    }
}
执行用时 :1 ms, 在所有 Java 提交中击败了77.97% 的用户内存消耗 :37.9 MB

2. 1~N中,中仅有一个数出现了一次,其余数出现K次。求出现了一次的数是多少。
思考:因为不知道K是偶数还是奇数,所以不能直接进行^运算,我们可以思考一个运算,使一个数出现K次后会被消0,这样我们将数组中的数进行该运算后剩下的便是只出现一次的数。
A?A?A?A?A?A…?A=0,我们发现n个相同的n进制数做不进位加法即可满足条件
然后我就自己写了一个不进位方法:

static int sum(int a,int b,int k) {
    String s = Integer.toString(a,k);
   // System.out.println(s);
    String s1 = Integer.toString(b,k);
   // System.out.println(s1);
    String sum = "";
    int i = s.length()-1;
    //System.out.println(i);
    int j = s1.length()-1;
    //System.out.println(j);
     int q = Math.abs(i-j);
   if(i > j) {
    int m = 0;
    for(; m < q;m++)
     sum+=s.charAt(m);
    for(int n = 0; n < s1.length();n++) {
     if(s.charAt(m)+s1.charAt(n)-96 >= k)
      sum+=s.charAt(m)+s1.charAt(n)-96-k;
     else
      sum+=s.charAt(m)+s1.charAt(n)-96;
    }
   }else if(i < j){
    int m = 0;
    for(; m < q;m++)
     sum+=s1.charAt(m);
    for(int n = 0; n < s.length();n++) {
     if(s1.charAt(m)+s.charAt(n)-96 >= k)
      sum+=s1.charAt(m)+s.charAt(n)-96-k;
     else
      sum+=s1.charAt(m)+s.charAt(n)-96;
    }
    
   }else {
    if(i == 0) {
     for(int n = s.length()-1; n >= 0 ;n--) {
     if(s1.charAt(n) + s.charAt(n)-96 >= k)
      sum+=s1.charAt(n)+s.charAt(n)-96-k;
     else
      sum+=s1.charAt(n)+s.charAt(n)-96;
    // System.out.println(sum);
     }
    }else {
     for(int n = 0; n < s.length() ;n++) {
      if(s1.charAt(n) + s.charAt(n)-96 >= k)
       sum+=s1.charAt(n)+s.charAt(n)-96-k;
      else
       sum+=s1.charAt(n)+s.charAt(n)-96;
     // System.out.println(sum);
    }  
    }
   }
    return Integer.parseInt(sum,k);
   }
   实现:
     static int singleNumber(int[] nums,int k) {
    if(nums.length <= 2)
     return nums[0];
    int count = sum(nums[0],nums[1],k);
    for(int i = 2; i < nums.length ; i++) {
     count = sum(count,nums[i],k);
    } 
    return count;
   }
   当然,这个我只考虑了正数的情况。如果是负数将有所不同。

leetcode相关题练习:
137. 只出现一次的数字 II

(摊手)因为要考虑负数的情况,所以感觉我自己写太麻烦了,又想不到怎么做,就暴力了
class Solution {
    public int singleNumber(int[] nums) {   
      Arrays.sort(nums);
        for(int i = 0; i < nums.length-1; ) {
           // System.out.println(nums[i]);
            if(nums[i] == nums[i+1])
                i=i+3;
            else 
                return nums[i];
        }
        return nums[nums.length-1];
    }
}
执行用时 :3 ms, 在所有 Java 提交中击败了60.65% 的用户内存消耗 :38 MB
官方题解:
class Solution {
    public int singleNumber(int[] nums) {   
      int ones = 0, twos = 0;
        for(int num : nums){
            ones = ones ^ num & ~twos;
            twos = twos ^ num & ~ones;
        }
        return ones;
    }
}

260. 只出现一次的数字 III

待更新

3. 一个数,求其二进制位上有几个一。
思考:遍历,有1则加。
或者 对于n来说,只要不为0,那么就一定有某个位上值为1,那么我们只要加一个1就将原数消一个1即1&(n-1);

static int Three(int n) {
        int count = 0;
        while(n != 0){
            n&=(n-1);
            ++count;
        }
        return count;
    }

leetcode相关题练习:
191,位1的个数

public class Solution {
    // you need to treat n as an unsigned value
    public int hammingWeight(int n) {
        int count = 0;
        while(n != 0){
            n&=(n-1);
            ++count;
        }
        return count;
    }
}
执行用时 :1 ms, 在所有 Java 提交中击败了99.91% 的用户内存消耗 :33.3 MB

4. 一个语句判断一个数是否是2的整数次幂。
思考:2的整数次幂即其二进制数中只有一个1。
即(x-1)&x ==0?0:1;

leetcode相关题:
231.2的幂

class Solution {
    public boolean isPowerOfTwo(int n) {
        if(n <= 0)
            return false;
        int temp = n&(n-1);
        boolean b = (temp == 0)?true:false;
        return b;
    }
}
执行用时 :1 ms, 在所有 Java 提交中击败了100.00% 的用户内存消耗 :33.7 MB

拓展:
326.3的幂

class Solution {
    public boolean isPowerOfThree(int n) {
        if(n<=0)
            return false;
        if(n==1)
            return true;
        while(n>1){
            if(n%3!=0)
                return false;
            n/=3;
        }
        return true;
    }
}
执行用时 :14 ms, 在所有 Java 提交中击败了99.58% 的用户内存消耗 :35.7 MB

342. 4的幂

class Solution {
    public boolean isPowerOfFour(int num) {
        if(num < 1)
            return false;
        if(num == 1)
            return true;
        while(num > 1){
            if(num%4!=0)
                return false;
            num/=4;
        }
        return true;
    }
}
执行用时 :1 ms, 在所有 Java 提交中击败了100.00% 的用户内存消耗 :33.5 MB

5. 0-1间的浮点数的二进制表示。
思考:列如小数0.625=0.5+0.125就是0.101。因为0.1= 2^(-1) = 0.5
0.001 = 2^(-3) = 1/8=0.125
所以将浮点数转化成二进制规则:[浮点数*2]

6. 将一个二进制数的奇偶位的数互换

你可能感兴趣的:(算法)