位運(yùn)算 算法

位運(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 ) % p

  • long (占 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)
    1. 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.
    1. 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);
        }
    }
}
26. Minimum Unique Word Abbreviation(411.leetcode)這一題是hard 難度[ 這題還是不太明白]
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,983評(píng)論 6 537
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 98,772評(píng)論 3 422
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 176,947評(píng)論 0 381
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經(jīng)常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,201評(píng)論 1 315
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 71,960評(píng)論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 55,350評(píng)論 1 324
  • 那天,我揣著相機(jī)與錄音,去河邊找鬼。 笑死,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,406評(píng)論 3 444
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 42,549評(píng)論 0 289
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 49,104評(píng)論 1 335
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 40,914評(píng)論 3 356
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 43,089評(píng)論 1 371
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,647評(píng)論 5 362
  • 正文 年R本政府宣布,位于F島的核電站,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 44,340評(píng)論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,753評(píng)論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,007評(píng)論 1 289
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 51,834評(píng)論 3 395
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 48,106評(píng)論 2 375

推薦閱讀更多精彩內(nèi)容