位運(yùn)算 算法
-1.與: &
或: |
非: !
異或 : ^ 相同為 0, 不同為 1
int 32 位 -> int 的范圍 -2^(31)to 2^ 31 - 1
long 64 位 -> long 的范圍 -2^(63) to 2^ 63 -1
=========================================
-2.補(bǔ)碼:
-x + 1 是 x 的 補(bǔ)碼
2 + 1111111111111111111111111111110 = 0000....0
=========================================
-3. 1 << n = 2 ^ n
n >> x = n/ (2 ^ x )
=========================================
-4. 把a(bǔ)rray of char 轉(zhuǎn)換成 String -> String.valueOf( arr)
-> new String(arr)
把 array of char 里的一個(gè)字符轉(zhuǎn)換Case -> Character.toUpperCase( arr[i] )
-> Character.toLowerCase( arr[i] )
=================================================
-5. "<<" : 左移運(yùn)算符,num << 1,相當(dāng)于num乘以2
">>": 右移運(yùn)算符,num >> 1,相當(dāng)于num除以2 (如果是負(fù)數(shù)補(bǔ)位是“1”, 正數(shù)補(bǔ)位是“0”)。
">>>": 無符號(hào)右移,忽略符號(hào)位,空位都以0補(bǔ)齊
=================================================
-6. 二進(jìn)制狀態(tài)壓縮
操作:???????? ???????? 運(yùn)算:
取出整數(shù) n 在二進(jìn)制下的第 k 位 ----> (n >> k) & 1
取出整數(shù) n 在二進(jìn)制表示下的第 0 ~ k - 1 位(后k位)---> n &((1 << k) -1)
把整數(shù) n 在二進(jìn)制表示下的第 k 位取反 ---> n ^( 1 << k)
把整數(shù) n 在二進(jìn)制表示下的第 k 位賦值1 ---> n | ( 1<< k)
把整數(shù) n 在二進(jìn)制表示下的第 k 位賦值0 ---> n &( ~( 1 << k ))
題目類型總結(jié):
1.直接問二進(jìn)制數(shù)的相關(guān)操作(翻轉(zhuǎn), 補(bǔ)碼,加法, 計(jì)算1bit 的總數(shù))
2.字符串的a到z, 或者 A到Z 的matching(前綴樹,字符串共同字符)
3.要操作的數(shù)字都是2的倍數(shù)(判斷指數(shù)是2或3或4, 二進(jìn)制表(時(shí)間),快速冪算法)
4.尋找二進(jìn)制數(shù)的規(guī)律(判斷alerting bits, )
1· 二進(jìn)制中1 的個(gè)數(shù)(15 劍指offer )
- 用 n = n & (n -1) 來檢測有幾個(gè) 1 在 二進(jìn)制數(shù)中, 時(shí)間復(fù)雜度 ,有幾個(gè) 1 s loop 就運(yùn)行幾次
public static int NumberOf1(int n) {
int count = 0;
while( n ) {
count ++;
n = (n- 1) & n;
}
return count;
}
2· 數(shù)值的整數(shù)次方(16 劍指offer )
- 用遞歸的形式, 求解
public static double PowerWithExp(double base, int exponent){
if(exponent == 1)
return base;
if(exponent == 0)
return 1;
double result = PowerWithExp( base, exponent >> 1 );
result * = result;
if((exponent & 0x1)== 1)
result *= base;
return result;
}
- 用 loop 的形式,求解
public static int int PowerExp(int base, int exponent) {
int res = 1, tmp = base;
while(exponent != 0) {
if( ( exponent & 0x1) == 1)
res = res * tmp;
tmp *= tmp;
exponent >>= 1;
}
return res;
}
3· 算法進(jìn)階 a^b % p
取模運(yùn)算的性質(zhì)
(a + b)% p = (a % p + b % p) % p
(a - b) % p = ( a % p - b % p) % p
(a ^ b) % p = ( ( a % p)^ b) % p
(a * b) % p = ( a % p * b % p ) % plong (占 8個(gè) 字節(jié))數(shù)據(jù)范圍變?yōu)椋?263~263-1 ; int(占4個(gè)字節(jié)) 數(shù)據(jù)范圍變?yōu)椋?2^31~ 2^31-1
快速冪算法: 把復(fù)雜度降到了 log b 次
3 * 3 * 3......* 3
3 ^ 7 = ?
3 ^ 1 = 3
3 ^ 2 = 9
3 ^ 4 = 81
3 ^ 1000000
3 ^ 1 = 3
3 ^ 2 = 9
3 ^ 4 = 81
3 ^ 8
3^( 2 ^ 19)=
2^k 次 3 的相乘
import java.util.*;
public static void main(String[] args) {
Scanner in = new Scanner(System.in);
int a = in.nextInt() , b = in.nextInt(), c = in.nextInt();
long res = 1 % p;
long tmp = a;
for(; b!= 0; b >> = 1) {
if( (b & 1 ) == 1) {
/* ( (a * b) % p = a % p * b % p ) % p */
res = res * tmp % p ;
}
tmp = tmp * tmp % p ;
}
System.out.println( res);
}
4· 算法進(jìn)階 a * b % p
- 因?yàn)橛袝r(shí)候當(dāng) a 和 b 的乘積 超過 - 2^ 63 to 2 ^ 63 -1; 就無法得到 a * b % p, 所以這里也需要用到 快速冪算法
a * b
a + a + a + a + .... + a
a * 1 = a
a * 2 = 2a
a * 4 = 4a
a * 8 = 8a
.....
a * ( 2 ^ k ) = 2 ^ k * a 就是 2^k 次 a 相加
時(shí)間復(fù)雜度: log b 次
import java.util.*;
public static void main(String [] args) {
Scanner in= new Scanner (System.in);
long a = in.nextInt(), b = in.nextInt(), c = in.nextInt();
long tmp = a;
long res = 0 % p;
while( b != 0) {
if( ( b & 1) == 1)
res = (res + tmp ) % p;
tmp = (tmp + tmp) % p;
b >> = 1;
}
return res;
}
5· Sum of two Integer(371 leetcode)
- 用 ^ 和 & 來完成 加法運(yùn)算
public static int getSum(int a, int b) {
return b == 0 ? a : getSum( a^b, (a & b )<< 1);
}
6·Single Number II (137 leetcode)
- 解題思路 把 所有element 以二進(jìn)制的形式 存入array 然后 mod 3. array 里留下來的數(shù), 就是結(jié)果。
class Solution {
public static int singleNumber(int[] nums) {
int[] res = new int[32];
for(int i=0; i<nums.length; i++){
int tmp = nums[i];
for(int j=res.length -1 ; j >=0 ;j--){
res[j] += tmp & 0x1;
tmp >>= 1;
}
}
for(int i =0; i<res.length; i++){
res[i] = res[i] % 3;
}
int a = 0;
for(int i=0 ; i< res.length ; i++){
a <<= 1;
a += res[i];
}
return a;
}
}
- 思路二:
public int singleNumber(int[] nums) {
int one = 0, two = 0;
for(int i : nums) {
one = (one ^ i) & ~two;
two = (two ^ i) & ~one;
}
return one;
}
7 · Power of Two(231 leetcode)
- 如果一個(gè)數(shù)的指數(shù)是2, 那么可以確定的是它的 二進(jìn)制表示是只有最高位是 1,其它位都是0.所以可以利用這一特性。如果n & (n - 1) == 0,那么可以確定這個(gè)數(shù)的二進(jìn)制表示是100000000,也就是2的指數(shù)。然后考慮邊界情況, 例如 n>0
class Solution {
public boolean isPowerOfTwo(int n) {
return n >0 && ( (n &( n-1) )== 0);
}
}
8 · Power of Four(342 leetcode)
- 如果一個(gè)數(shù)的指數(shù)是4, 那么第一可以確定它的 二進(jìn)制表示是只有最高位是 1,其它位都是0。 可以用上面 power of two 的方法用 ( n & (n -1)) == 0. 然后 如果是指數(shù)為4的話,所以1 bit 永遠(yuǎn)在 odd 的位置 0101。 所以 0X55555555 可以get rid of those power of 2.
public boolean isPowerOfFour(int num) {
return num > 0 && (num &(num -1) == 0 ) && ((num & 0x55555555) == num );
}
9 · Power of Three (326 leetcode)
- 解題思路 這里只能用常規(guī)的解題思路, 用loop 循環(huán) 因?yàn)? 不是2 的倍數(shù), 不斷取余,直到取余結(jié)果不等于0, 就結(jié)束loop。當(dāng)結(jié)果不為1時(shí),就說明 n 不是 power of three。
public static boolean isPowerOfThree(int n) {
if(n <= 0)
return false;
while( n % 3 == 0) {
n /= 3;
}
return n == 1;
10 · Bitwise AND of Numbers Range (201 leetcode)
- last bit of ( odd number & even number) is 0
- 2.when m != n, there is at least an odd number and even number , so the last bit position result is 0.
- move m , n to right position 直到 m == n, 因?yàn)楫?dāng) m != n 時(shí), 說明中間必然存在 odd number 和 even number 說明一定是0, 當(dāng) m == n 時(shí),可以keep 當(dāng)前 bits
public int rangeBitwiseAnd(int m, int n) {
if( m == 0)
return 0;
int moveFactor = 0 ;
while( m != n) {
m >>= 1;
n >>=
}
}
11 · Maximum XOR of Two Numbers in an Array (421 leetcode)
- 這道題使用到了 Trie 樹(前綴樹 或者 字典樹)+ 分治法
1.Trie 的強(qiáng)大之處就在于它的時(shí)間復(fù)雜度。它的插入和查詢時(shí)間復(fù)雜度都為 o(K), 其中 K 為key 的長度, 與Trie中保存了多少個(gè)元素?zé)o關(guān)。
2.字典樹(Trie)可以保存一些字符串-> 值的對(duì)應(yīng)關(guān)系。基本上,它跟Java 的HashMap 功能相同,都是 key-value 映射,只不過Trie 的key 只能是字符串。
3. Trie 樹,又稱單詞查找樹或鍵樹,是一種樹形結(jié)構(gòu)。典型應(yīng)用 是用于統(tǒng)計(jì)和排序大量的字符串,所以經(jīng)常被搜索引擎系統(tǒng)用于文本詞頻統(tǒng)計(jì)。 它的優(yōu)點(diǎn)是: 最大限度地減少無謂的字符串比較,查詢效率比哈希表高。
4. Trie 的核心思想是空間換時(shí)間。 利用字符串的公共前綴來降低查詢時(shí)間的開銷以達(dá)到提高效率的目的。 - 解題思路 根據(jù)題目描述, 我們需要找到最大的異或值,異或代表了兩個(gè)數(shù)的二進(jìn)制的不同程度,且越高位越不一樣,異或值就越大,由于是按位比較,所以使用Trie 樹來當(dāng)做基礎(chǔ)數(shù)據(jù)結(jié)構(gòu)。
我們可以總結(jié)出以下幾點(diǎn):
1.因?yàn)檎偷奈粩?shù)是固定的,排除第一位符號(hào)位,Trie樹的高度是常數(shù)的,即最高32層(包括root)。
2. 由于只有0 和 1 兩個(gè)子節(jié)點(diǎn),所以為了節(jié)省空間,可以使用 二叉樹 的方式(或者數(shù)組或 HashMap 均可)
3. 由于是異或,前綴為如果相同,異或值都是0,所以可以先找到第一個(gè) 兩個(gè)字節(jié)都不為空的節(jié)點(diǎn)當(dāng)做root。
class Solution{
class TrieNode{
int val;
TrieNode zero, one;
boolean isEnd;
}
class TrieTree{
TrieNode root;
public TrieTree() {
root = new TrieNode();
}
public void insert(int num){
TrieNode cur = root;
int j = 1 << 30;
for(int i=0; i<31; i++){
/*根據(jù) num 在 j 位置的數(shù)目判斷應(yīng)該向 0 還是向 1 */
int b = num & j == 0 ? 0 : 1 ;
TrieNode node = new TrieNode();
if( b == 1 && cur.one == null )
cur.one = new TrieNode();
if( b == 0 && cur.zero == null )
cur.zero = new TrieNode();
cur = b == 0 ? cur.zero : cur.one;
j >> 1;
} /* for loop */
cur.isEnd = true;
cur.val = num;
}
public int findMaximumXOR(int[] nums) {
if( nums == null || nums.length <= 1)
return 0;
TrieTree tree = new TrieTree();
for(int val : nums){
tree.insert(val);
}
/* 獲取真正需要開始判斷的root */
TrieNode cur = tree.root;
while( cur.one == null || cur.zero == null) {
cur = cur.zero == null ? cur.one : cur.zero;
}
return maxHelper( cur.zero , cur.one )
}
/* 分治法, 原則就是使兩個(gè)分支的高位不同
1. 當(dāng)1分支的下一位只有1時(shí),找 0 分支的0, 若沒有就找1;
2. 當(dāng)1分支的下一位只有0 時(shí),找 0 分支的1, 若沒有就找0;
3. 當(dāng)1分支的下一位有0 和 1時(shí), 看0 分支, 如果0 分支只有 1 ,則1分支走1,反之走0.
4. 當(dāng)0,1兩個(gè)分支均有兩個(gè)下一位時(shí),嘗試【1分支走1,0分支走0】和【1分支走0,0分支走1】兩條路線并取最大值
*/
public int maxHelper(TrieNode zero , TrieNode one) {
if(zero.isEnd && one.isEnd)
return zero.val ^ one.val;
if( one.zero == null)
return maxHelper( one.one, zero.zero != null ? zero.zero : zero.one );
else if(one.one == null)
return maxHelper( one.zero , zero.one != null ? zero.one : zero.zero);
else if(zero.zero == null)
return maxHelper( one.zero, zero.one);
else if (zero.one == null)
return maxHelper( one.one, zero.zero);
else
return Math.max( maxHelper( zero.one , one.zero ), maxHelper( zero.zero, one.one ));
}
}
}
12 · Number Complement (476 leetcode)
- 解題思路 從num 的最低位一步步 遍歷到最高位, 通過 或 mask 變量。
public int findComplement(int num) {
if(num == 0)
return 1;
int mask = 1;
int ret = 0;
while( num != 0) {
if( num & 1 == 0 )
ret |= mask;
mask <<= 1;
num >>= 1;
}
return ret;
}
13 · Missing Number (268 leetcode)
- 解題思路 使用連加公式, 1+2+3+...+ 100 -> (上底 + 下底) * 高 / 2 -> (1 + 100)* 100 /2
public int missingNumber(int[] nums) {
if(nums == null)
return 0;
int sum = (nums.length + 1)*nums.length/2;
for(int val : nums)
sum -= val;
return sum;
}
14 · Maximum Product of Word Lengths(318. leetcode)
- 解題思路 把每個(gè)string 都轉(zhuǎn)換成 一個(gè) 二進(jìn)制表示的int 值, 如果 兩個(gè) 二進(jìn)制表示的int 值 相互 “ & ”的結(jié)果是0 , 則表示 字符串沒有重復(fù)的 ;a 到 z 的 26個(gè)字母 可以全部用 1<<( char - 'a'), 來表示 因?yàn)閕nt 有 32 位, 而 a 到 z 里面 z 需要向左位移25位,因?yàn)?32 > 25 所以正好能被全部cover。
public int maxProduct(String[] words) {
if(words == null)
return 0;
int[] value = new int[words.length];
for(int i =0; i< words.length ; i++) {
for(int j = 0; i < words[i].length; j++) {
value[i] |= 1 << (words[i].charAt(j) - 'a');
}
}
int max = 0 ;
int tmp = 0 ;
for(int i =0 ; i<value.length; i++) {
for(int j = i+1 ; j < value.length; j++) {
if( (value[i] & value[j]) == 0) {
tmp = words[i].length() * words[j].length();
max = max > tmp ? max : tmp;
}
}
}
return max;
}
15 · Reverse Bits(190. leetcode)
- **解題思路 ** 這一題與第14 題, 的差別是第14題是求補(bǔ)碼, 把32 位都考慮在內(nèi), 但是 這道必須注意 一定要 向左移滿 32位
public int reverseBits(int n) {
int ret = 0;
for(int i=0; i<32; i++) {
ret |= n & 1;
n >>= 1;
if (i < 31)
ret <<= 1;
}
return ret;
}
16 · Binary Watch (401. leetcode)
這道題不是很明顯的 bit manipulation 的類型問題
1.需要列出所有時(shí)間組合的可能性
-2.所有可能性里面要剔除 不符合條件的組合例如 h > 11或 minutes > 59
-3. 輸出的string format 要注意。java 語法注意點(diǎn) 創(chuàng)建List或者M(jìn)ap的時(shí)候指定類型與不指定類型有什么區(qū)別
-例:List list = new ArrayList();
List<String> list = new ArrayList<String>();
創(chuàng)建一個(gè)Map
Map map = new HashMap();
Map<String,String> map = HashMap<String,String>();其實(shí)指定了參數(shù)類型編譯器在編譯期間就會(huì)幫助你檢查存入容器的對(duì)象是不是參數(shù)類型!不是就會(huì)報(bào)錯(cuò)!保證了類型安全!性能上沒什么影響,因?yàn)榉盒驮谶\(yùn)行期間會(huì)擦除!就是說用不用類型參數(shù)在運(yùn)行期間編譯后的運(yùn)行代碼是一樣的!
解題思路: 運(yùn)用*backtracking *的解法
1.判斷的base case 終止條件: hour 超過 11, minutes 超過 59
2.當(dāng)hour 和 minutes 符合條件時(shí),把當(dāng)前結(jié)果加入到 list 里面。
3.hour: 8,4,2,1 ; minutes:32,16,8,4,2,1 都是以2為指數(shù)可以用 1<< i 表示
public List<String> readBinaryWatch(int num) {
List res = new ArrayList<String>();
if(num == null)
return res;
generate(num, res, 0,0,0,0);
return res;
}
public void generate(int n, List<String> res, int hour, int minutes, int i, int j) {
if(hour > 11 || minutes > 59) return;
if(n == 0)
res.add( hour+":" + minutes>10? "": "0" + minutes);
else{
while(j < 6){
generate( n-1, res, hour, minutes+ 1 << j, i, j+1);
j++;
}
while(i < 4){
generate( n-1, res, hour + 1<< i , minutes, i+1, j);
i++;
}
} /*else */
}
16 · Integer Replacement(397. leetcode)
- 1.當(dāng) n 是 even 的時(shí)候, 需要進(jìn)行的操作是 fixed, 問題就在于 當(dāng) n 是odd 的時(shí)候,需要判斷是 n+1 或是 n-1 。 雖然 backtracking 也是一種解法,但是時(shí)間復(fù)雜度較高, 所以這里有另外一種更好的解法。
-解題思路: 當(dāng) n 是 odd 時(shí),n = 2k + 1, n+1 = 2k+2, n-1 = 2k . Then (n+1)/2 = k+1, (n-1)/2 = k. 所以其中有一個(gè)是奇數(shù), 另一個(gè)是偶數(shù)。 我們的目標(biāo)是 盡可能的除以2, 所以我們要在 k 和 k+1 中選擇 偶數(shù), 所以我們要 除以4。 但這里有個(gè)special case n = 3, 我們要選擇 n-1 而不是 n+1
public int integerReplacement(int n) {
if( n == Integer.MAX_VALUE)
return 32;
int ret = 0 ;
while( n != 1) {
if( ( n & 1) == 0)
n >>= 1;
else {
if( n == 3 || (n -1 ) % 4 == 0) n--;
else {
n++;
}
}
ret ++;
}
return ret;
}
17·Binary Number with Alternating Bits (693.leetcode)
-
解題思路: 采用 “ ^” 的特性 相同為0 不同為 1, 讓 d 在 0 與 1 之間相互切換. 若 d ^= 1 ,
當(dāng) d = 0, d ^= 1 -> d =1;
當(dāng) d = 1, d^= 1 -> d = 0; - 0 ^ 0 = 0
- 1 ^ 0 = 1;
public boolean hasAlternatingBits(int n) {
int d = n & 1;
while( (n & 1) == d) {
d ^= 1;
n >>= 1;
}
return n == 0;
}
- 方法二 : 因?yàn)?“ ^ ” 之后結(jié)果全為1 的話, 說明每一位都不一樣 所以結(jié)果就都是1, 然后 在return的時(shí)候檢查 a==1111, a+1=10000, a&(a+1)==0。
public boolean hasAlternatingBits(int n) {
int a = ( n ^ ( n >> 1) );
return ( a & ( a + 1)) == 0;
}
18· IP to CIDR (751.leetcode)
-
解題思路:
-由于題目中要求盡可能少的使用CIDR塊,那么在n確定的情況下,CIDR塊能覆蓋的越多越好。根據(jù)我們前面的分析,當(dāng)CIDR塊斜杠后面的數(shù)字越小,該塊覆蓋的ip地址越多。那么就是說相同前綴的個(gè)數(shù)越少越好,但是我們的ip地址又不能小于給定的ip地址,所以我們只能將0變?yōu)?,而不能將1變?yōu)?。 -
解題目標(biāo):
-1.用 long 來存放32 位的二進(jìn)制數(shù)
-2.找到二進(jìn)制數(shù)的末尾的1的位置,因?yàn)橹荒馨?變1,不能把1變0
-3.得到能潛在覆蓋的個(gè)數(shù)是否小于或等于要求覆蓋的個(gè)數(shù)
-4.得到當(dāng)前的start ip 地址 能夠覆蓋的地址,然后轉(zhuǎn)換成 CIDR 的形式
public List<String> ipToCIDR(String ip, int range) {
long x = 0;
List<String > list = new ArrayList<String>();
String[] ips = ip.split(".");
/* 把32位的二進(jìn)制放到 long 里面 */
for(int i = 0; i < ips.length; i++) {
x = Integer.parseInt( ips[i]) + ( x << 8);
}
while( range > 0) {
long step = x & -x;
while(step > range) step >>= 1;
list.add( ipToString(x, (int) step) );
x += step;
range -= step;
}
return list;
}
public String ipToString( long x, int step) {
int[] ans = new int[4];
for(int i=0; i< ans.length; i++) {
ans[i] = x & 255;
x >>= 8;
}
int len = 32;
while(step > 1) {
step >>= 1;
len --;
}
return ans[3] +"."+ ans[2] +"."+ ans[1] +"."+ ans[0] +"\"+len;
}
19. Letter Case Permutation (784.leetcode)
-
解題思路:
-BFS:用一個(gè)queue 來實(shí)現(xiàn) BFS
public List<String> letterCasePermutation(String S) {
if(S == null) return new LinkedList<String>();
Queue<String> queue = new LinkedList<String>();
queue.offer(S);
for(int i=0; i< S.length(); i++) {
if( Character.isDigit(S.charAt(i))); continue;
int size = queue.size();
for(int j =0; j<size;j++) {
String cur = queue.poll();
int[] curArr = cur.tocharArray();
curArr[i] = Character.toUpperCase(curArr[i]);
queue.add(String.valueOf(curArr));
curArr[i] = Character.toLowerCase(currArr[i]);
queue.add(String.valueOf(curArr));
}
}
return new LinkedList<>(queue);
}
-
解題思路:
-DFS
public List<String> letterCasePermutation(String S) {
if(S == null ) return null;
List<String> res = new ArrayList<String>();
char[] cur = S.toCharArray();
helper(res, S, 0 );
return res;
}
public void helper(List<String> res , char[] cur, int pos ) {
if(pos == S.length) {
res.add( new String(cur));
return;
}
if( Character.isDigit( cur[pos] )) {
helper( res, cur, pos + 1);
return;
}
cur[pos] = Character.isLowerCase(cur[pos]);
helper(res, cur, pos +1 );
cur[pos] = Character.isUpperCase(cur[pos]);
helper(res, cur, pos + 1);
}
20. Bitwise ORs of Subarrays (898.leetcode)
- array 里的元素,相互組合得到OR 的結(jié)果,最后output 有幾個(gè)不同結(jié)果。這里是
-解題思路:
-1.只能0變1 , 不能1變0,因?yàn)槭? OR'
public int subarrayBitwiseORs(int[] A) {
Set<Integer> ans = new HashSet();
Set<Integer> cur = new HashSet();
cur.add(0);
for(int x : A) {
Set<Integer> cur2 = new HashSet();
for(int y : cur) {
cur2.add( x | y);
}
cur2.add(x);
cur = cur2;
ans.addAll( cur);
}
return res;
}
21. Prime Number of Set Bits in Binary Representation (762.leetcode)
-解題思路:因?yàn)樗械臄?shù)字都是用32個(gè)bits 表示,通過計(jì)算有幾個(gè)數(shù)的bits 個(gè)數(shù)是prime number。 所以bits 個(gè)數(shù)會(huì)在[0, 32] 區(qū)間內(nèi)。[0,32] 的區(qū)間內(nèi) 2,3,5,7,9,11,13,17,19,23,29 是prime number。所以可以把這個(gè)映射在bits的位置上 0010100010100010101100 -> 665772 (十進(jìn)制)
2nd,3rd,5th,7th,11th,13th,17th,19th,23rd and 29th bits are 1。
-注意的細(xì)節(jié)
-1.>> 的優(yōu)先級(jí) 高于 &
-2.L++ 是先算L,然后再++
-3.查看一個(gè)小于32 的數(shù)字是否存在,可以用一下方法
public int countPrimeSetBits(int L, int R) {
int res = 0;
while(L <= R) {
res += 665772 >> Integer.bitCount(L++) &1;
}
return res;
}
22.Convert a Number to Hexadecimal (405.leetcode)
-主要解決問題:
-1. 把32 位的bits, 拆分到array 里面
-2. 把 array of char 用正確的順序放到string里面
-3. 把 [10, 15] 隱射到[a,f]
-4.這里最好用 >>> 而不是 >>, 因?yàn)楫?dāng) num 是負(fù)數(shù)的時(shí)候,>> 的補(bǔ)位永遠(yuǎn)是“1”, 所以while loop 永遠(yuǎn)不會(huì)結(jié)束。
public String toHex(int num) {
char [] map = {'0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f'};
String str = "";
while(num >0) {
int index = num & 15;
str = map[index] + str;
num >>>= 4;
}
return str;
}
23.Total Hamming Distance(477.leetcode)
-解題思路:
-這道題提別的做法是,一共是 1 到32 位,,首先 遍歷n 個(gè) 元素, 之后記錄每位有多少個(gè)1。這就意味著, 在每一位上有k個(gè)1 bit,就說明有 (n-k)個(gè) 是在這一位是不一樣的, 所以在每一位上就有 k *( n - k) 個(gè) hamming distance 。
public int totalHammingDistance(int[] nums) {
int total = 0;
int mask = 1;
int bitCount = 0;
for(int i = 0; i<30;i++) {
mask <<= i;
for(int val : nums)
if((val & mask) == 1) bitCount++;
total += bitCount * ( nums.length - bitCount);
bitCount =0;
}
return total;
}
24. Valid Word Abbreviation(408.leetcode)這一題和之后的2題是follow up
-.在比較兩個(gè)string 的pattern的時(shí)候,例如和數(shù)字之間的pattern, 可以用O(n)解決。 一個(gè)是 detail string , 還有一個(gè)是 abbrev string
-解題思路: 直接 遍歷其中的abbev string , 然后一一對(duì)照word string 檢查。
public boolean validWordAbbreviation(String word, String abbr) {
int n = word.length(), index =0, num=0;
for(int i=0; i<abbr.length(); i++) {
char ch = abbr.charAt(i);
if( Character.isDigit(ch)) {
if( ch == '0' && (i ==0 || !Character.isDigit(abbr.charAt(i-1))))
return false;
num = num * 10 + (ch - '0');
}
else{
index += num;
num =0;
if(index >= word.length() || word.charAt(index) != ch)
return false;
index ++;
}
index += num;
return index == n;
}
}
25. Generalized Abbreviation( 320.leetcode)這一題是medium 難度[ 這題還是不太明白]
class Solution {
public List<String> generateAbbreviations(String word){
List<String> ret = new ArrayList<String>();
backtrack(ret, word, 0, "", 0);
return ret;
}
private void backtrack(List<String> ret, String word, int pos, String cur, int count){
if(pos==word.length()){
if(count > 0) cur += count;
ret.add(cur);
}
else{
backtrack(ret, word, pos + 1, cur, count + 1);
backtrack(ret, word, pos+1, cur + (count>0 ? count : "") + word.charAt(pos), 0);
}
}
}