【OfferX】二进制

1.二进制中1的位数

题目:

数组中所有数对的汉明距离

题目:477. Total Hamming Distance

:统计第0位上的汉明距离,第1位上的汉明距离,… 第32位上的汉明距离, 它们的和就是总的汉明距离。
第i位的汉明距离,等于该位上1和0组合的不同个数,等于1的个数乘以0的个数。

Integer.bitCount

public static int bitCount(int i) {
        // HD, Figure 5-2
        i = i - ((i >>> 1) & 0x55555555);
        i = (i & 0x33333333) + ((i >>> 2) & 0x33333333);
        i = (i + (i >>> 4)) & 0x0f0f0f0f;
        i = i + (i >>> 8);
        i = i + (i >>> 16);
        return i & 0x3f;
    }

Long.bitCount

public static int bitCount(long i) {
        // HD, Figure 5-14
        i = i - ((i >>> 1) & 0x5555555555555555L);
        i = (i & 0x3333333333333333L) + ((i >>> 2) & 0x3333333333333333L);
        i = (i + (i >>> 4)) & 0x0f0f0f0f0f0f0f0fL;
        i = i + (i >>> 8);
        i = i + (i >>> 16);
        i = i + (i >>> 32);
        return (int)i & 0x7f;
     }

1.对于较长的二进制数据使用BitSet

题目:1178. Number of Valid Words for Each Puzzle

给定两个字符串数组A和B,如果对B中的一个字符串p,A的所有字符串w都满足如下条件:
I. w的所有字符都出现在p中
II. p的第一个字符出现在w中
对B中的每一个字符串B[i],求A中满足上述条件的数目

使用java.lang.BitSet

class Solution {
    boolean[][] wordChars;
    boolean[][] puzzleChars;
    public List<Integer> findNumOfValidWords(String[] words, String[] puzzles) {
        int n = words.length;
        int m= puzzles.length;
        List<Integer> ans = new ArrayList<>(m);
      
        // wordSet[i] is a set of puzzles that contains i
        BitSet[] wordSet = new BitSet[26];
        for(int i=0;i<m;++i){
            for(int j=0,jn=puzzles[i].length();j<jn;++j){
                int c = puzzles[i].charAt(j) - 'a';
                if(wordSet[c]==null){
                    wordSet[c] = new BitSet(n);
               }
                wordSet[c].set(i);
            }
        }
        // check each word if they are in puzzles
        // check each word if one character is the start of a puzzle
        for(int i=0;i<m;++i){
            ans.add(0);
        }
        boolean[] visited = new boolean[26];
        BitSet set = new BitSet(m);
        for(int i=0;i<n;++i){
            boolean empty = false;
            // reset all to 1
            set.set(0,m);
            for(int j=0,jn=words[i].length();j<jn;++j){
                int c = words[i].charAt(j) - 'a';
                if(visited[c]){
                    continue;
                }
                visited[c]=true;
                if(wordSet[c]==null){
                    empty = true;
                    break;
                }
                set.and(wordSet[c]);
                if(set.isEmpty()){
                    break;
                }
            }
            if(!empty){
                set.stream().forEach(k->{
                    if(visited[puzzles[k].charAt(0)-'a']){
                        ans.set(k, ans.get(k)+1);
                    }
                });
            }
            for(int j=0;j<26;++j){
                visited[j] =false;
            }
        }
        return ans;
    }
}

2.二分背包

题目: 1125. Smallest Sufficient Team

:如果 t 可以通过 t1|p1, t2|p2, t3|p3运算而来,则可知t的值就是三者的最小值: f(t) = min { f(t1|p1), f(t2|p2), f(t3|p3) } + 1.
我们只需要确保在求t的值时,所有t1,t2,t3的值已经确定。为了做到这一点,我们确保求t的过程中是递增的,就是 t=t1|p1 > t1.
为什么要确保这个顺序呢?为了避免后续重新更新t1,造成t也需要更新。(退回到Bellman-Ford算法的SPFA实现).
为了证明这个顺序,我们使用归纳法证明,如果求解的集合是 {t1,t2,t3, …}, 取集合中任意ti结合pi产生t=ti|pi, 且t不属于该集合,ti属于该集合。则显然t的解是确定的 。

class Solution {
    public int[] smallestSufficientTeam(String[] req_skills, List<List<String>> people) {
        int n = req_skills.length;
        int size = 1<<n;
        int m = people.size();
        
        Map<String,Integer> mp = new HashMap<>(n);
        for(int i=0;i<n;++i){
            mp.put(req_skills[i], i);
        }
        
        int[] pbit = new int[m];
        for(int i=0;i<m;++i){
            for(String s:people.get(i)){
                pbit[i] |= 1<<mp.get(s);
            }
        }
        long[] dp = new long[size];
        Arrays.fill(dp,-1L);
        dp[0] = 0;
        
        for(int i=0;i<size;++i){
            for(int j=0;j<m;++j){
                int nextState = i|pbit[j];
                if(nextState != i && (dp[nextState]==-1L ||(Long.bitCount(dp[i])+1 < Long.bitCount(dp[nextState])  ))){
                    dp[nextState] = dp[i] | (1L<<j);
                }
            }
        }
        long s = dp[size-1];
        int[] res = new int[Long.bitCount(s)];
        int idx=0;
        for(int i=0;i<m;++i){
            if( (s&1)==1){
                res[idx++]=i;
            }
            s>>>=1;
        }
        return res;
    }
}

3.x+y=x|y

题目:给定x,求第k个满足x+y=x|y的数
:x+y=x|y的充分必要条件就是x和y之间不存在任何同时为1的位。

import java.util.Scanner;
public class Main{
    public static void main(String[] args){
        Scanner scanner = new Scanner(System.in);
        long x = scanner.nextLong();
        long k = scanner.nextLong();
        long t = ~x;
        long mask = 1;
        for(int i=0;i<64;++i, mask<<=1){
            if((mask & t)==0)continue;
            if( (k&1)==0){
                // clear ith bit
                t &= (~mask);
            }
            k>>>=1;
        }
        System.out.println(t);
    }
}

4. x xor y > m (使用Trie,TODO完善说明)

题目

给定整数m以及n各数字A1,A2,…An,将数列A中所有元素两两异或,共能得到n(n-1)/2个结果,请求出这些结果中大于m的有多少个。

:字典树,比较一棵树等于比较多个子串,大大减少了冗余比较,在字典树节点中记录。分支中0,1的数量,对于每个串先比较再插入。

import java.util.Scanner;
public class Main{
    static class Trie{
        Trie[] chi=new Trie[2];
        int[] cnt=new int[2];
    }
    public static void main(String[] arg){
        Trie root=new Trie();        
        Scanner sc=new Scanner(System.in);
        int n=sc.nextInt();
        int m=sc.nextInt();
        long count=0;
        while(sc.hasNext()){
           int num=sc.nextInt();
           Trie cur=root;
           for(int i=20;cur!=null&&i>=0;i--){
               int a=1&(m>>i);
               int b=1&(num>>i);
               if(a==0&&b==0) count+=cur.cnt[1];
               if(a==0&&b==1) count+=cur.cnt[0];
               cur=cur.chi[a^b];//b^x=a,->b^a=x
           } 
           cur=root;
           for(int i=20;i>=0;i--){
               int b=1&(num>>i);
               if(cur.chi[b]==null) cur.chi[b]=new Trie();
               cur.cnt[b]++;
               cur=cur.chi[b];  
           }  
        }
        System.out.println(count);
    }
}

5. 一个数最接近的下一个2的幂

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值