publicclassSolution {// you need treat n as an unsigned valuepublicintreverseBits(int n) {int rev =0;for(int i=0; i<32&& n!=0; i++){ rev |=(n&1)<<(31-i); n >>>=1; }return rev; }}
解法2.位运算分治
publicclassSolution {privatestaticfinalint M1 =0x55555555; // 01010101010101010101010101010101privatestaticfinalint M2 =0x33333333; // 00110011001100110011001100110011privatestaticfinalint M4 =0x0f0f0f0f; // 00001111000011110000111100001111privatestaticfinalint M8 =0x00ff00ff; // 00000000111111110000000011111111publicintreverseBits(int n) { n = n >>>1& M1 | (n & M1) <<1; n = n >>>2& M2 | (n & M2) <<2; n = n >>>4& M4 | (n & M4) <<4; n = n >>>8& M8 | (n & M8) <<8;return n >>>16| n <<16; }}
publicclassSolution {// you need to treat n as an unsigned valuepublicinthammingWeight(int n) {int cnt=0;while(n!=0){ cnt += (n &1); n >>>=1; }return cnt; }}
如何求出 x 呢?我们可以从字典树的根节点开始进行遍历,遍历的「参照对象」为 ai。在遍历的过程中,我们根据 ai的第 x个二进制位是 0 还是 1,确定我们应当走向哪个子节点以继续遍历。假设我们当前遍历到了第 k 个二进制位:
如果 ai 的第 k 个二进制位为 0,那么我们应当往表示 1 的子节点走,这样 0⊕1=1,可以使得 x 的第 k 个二进制位为 1。如果不存在表示 1 的子节点,那么我们只能往表示 0 的子节点走,x 的第 k个二进制位为 0;
如果 ai的第 k 个二进制位为 1,那么我们应当往表示 0 的子节点走,这样 1⊕0=1,可以使得 x 的第 k 个二进制位为 1。如果不存在表示 0 的子节点,那么我们只能往表示 1 的子节点走,x 的第 k 个二进制位为 0。
由于字典树中的每个节点最多只有两个子节点,分别表示 0 和 1,因此本题中的字典树是一棵二叉树。在设计字典树的数据结构时,我们可以令左子节点 left 表示 0,右子节点 right 表示 1。
classSolution {// 字典树的根节点Trie root =newTrie();// 最高位的二进制位编号为 30staticfinalint HIGH_BIT =30;publicintfindMaximumXOR(int[] nums) {int n =nums.length;int x =0;//添加一个,check一个,为啥呢?因为i和j是有顺序的,j在i后面。for (int i =1; i < n; ++i) {// 将 nums[i-1] 放入字典树,此时 nums[0 .. i-1] 都在字典树中add(nums[i -1]);// 将 nums[i] 看作 ai,找出最大的 x 更新答案 x =Math.max(x,check(nums[i])); }return x; }publicvoidadd(int num) {Trie cur = root;for (int k = HIGH_BIT; k >=0; --k) {int bit = (num >>> k) &1;if (bit ==0) {if (cur.left==null) {cur.left=newTrie(); } cur =cur.left; }else {if (cur.right==null) {cur.right=newTrie(); } cur =cur.right; } } }publicintcheck(int num) {Trie cur = root;int x =0;for (int k = HIGH_BIT; k >=0; --k) {int bit = (num >>> k) &1;if (bit ==0) {// a_i 的第 k 个二进制位为 0,应当往表示 1 的子节点 right 走if (cur.right!=null) { cur =cur.right; x = x *2+1; } else { cur =cur.left; x = x *2; } } else {// a_i 的第 k 个二进制位为 1,应当往表示 0 的子节点 left 走if (cur.left!=null) { cur =cur.left; x = x *2+1; } else { cur =cur.right; x = x *2; } } }return x; }}classTrie {// 左子树指向表示 0 的子节点Trie left =null;// 右子树指向表示 1 的子节点Trie right =null;}
给定一个表示 DNA序列 的字符串 s ,返回所有在 DNA 分子中出现不止一次的 长度为 10 的序列(子字符串)。你可以按 任意顺序 返回答案。
classSolution {staticfinalint L =10;publicList<String> findRepeatedDnaSequences(String s) {List<String> ans =newArrayList<String>();Map<String,Integer> cnt =newHashMap<String,Integer>();int n =s.length();for (int i =0; i <= n - L; ++i) {String sub =s.substring(i, i + L);cnt.put(sub,cnt.getOrDefault(sub,0) +1);if (cnt.get(sub) ==2) {ans.add(sub); } }return ans; }}
318.最大单词长度乘积
给你一个字符串数组 words ,找出并返回 length(words[i]) * length(words[j]) 的最大值,并且这两个单词不含有公共字母。如果不存在这样的两个单词,返回 0 。
解法:如果可以将判断两个单词是否有公共字母的时间复杂度降低到 O(1)?
由于单词只包含小写字母,共有 26个小写字母,因此可以使用位掩码的最低 26 位分别表示每个字母是否在这个单词中出现。将 a 到 z 分别记为第 0 个字母到第 25 个字母,则位掩码的从低到高的第 i 位是 1 当且仅当第 i 个字母在这个单词中,其中 0≤i≤25 。