1. 程式人生 > >leetcode-461-漢明距離(hamming distance)-java

leetcode-461-漢明距離(hamming distance)-java

題目及測試

package pid461;
/* 漢明距離

兩個整數之間的漢明距離指的是這兩個數字對應二進位制位不同的位置的數目。

給出兩個整數 x 和 y,計算它們之間的漢明距離。

注意:
0 ≤ x, y < 231.

示例:

輸入: x = 1, y = 4

輸出: 2

解釋:
1   (0 0 0 1)
4   (0 1 0 0)
       ↑   ↑

上面的箭頭指出了對應二進位制位不同的位置。




*/

import java.util.List;

public class main {
	
	public static void main(String[] args) {
		int [] testTable = {1,8,21};
		int [] testTable2 = {4,9,32};
		for(int i=0;i<testTable.length;i++){
			test(testTable[i],testTable2[i]);
		}
	}
		 
	private static void test(int ito,int ito2) {
		Solution solution = new Solution();
		int rtn;
		long begin = System.currentTimeMillis();
		System.out.print(ito+"  ");
		System.out.print(ito2);
		System.out.println();
		//開始時列印陣列
		
		rtn= solution.hammingDistance(ito,ito2);//執行程式
		long end = System.currentTimeMillis();	
		
		System.out.println("rtn=" );
		System.out.print(rtn);	
		System.out.println();
		System.out.println("耗時:" + (end - begin) + "ms");
		System.out.println("-------------------");
	}

}

解法1(成功,7ms,超快)
漢明距離,求1的個數的那個物件,實際是x與y的亦或結果
亦或完後通過,與1進行與運算,如果為1,末尾為1
然後>>>1,向右移動一位,相當於除以2

package pid461;

import java.util.Arrays;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map.Entry;

public class Solution {
public int hammingDistance(int x, int y) {
    int num=x^y;
    int result=0;
    while(num!=0){
    	if((num&1)==1){
    		result++;
    	}
    	num>>>=1;
    }
	
	
	return result;
    }
}

其他人的演算法,亦或沒有區別,有區別的是求1的個數的演算法
1 我們先判斷整數的最右邊一位是不是1。接著把整數右移一位,原來處於右邊第二位的數字現在被移到第一位了,再判斷是不是1。這樣每次移動一位,直到這個整數變成0為止。現在的問題變成怎樣判斷一個整數的最右邊一位是不是1了。很簡單,如果它和整數1作與運算。由於1除了最右邊一位以外,其他所有位都為0。因此如果與運算的結果為1,表示整數的最右邊一位是1,否則是0

2 這個思路當輸入i是正數時沒有問題,但當輸入的i是一個負數時,不但不能得到正確的1的個數,還將導致死迴圈。以負數0x80000000為例,右移一位的時候,並不是簡單地把最高位的1移到第二位變成0x40000000,而是0xC0000000。這是因為移位前是個負數,仍然要保證移位後是個負數,因此移位後的最高位會設為1。如果一直做右移運算,最終這個數字就會變成0xFFFFFFFF而陷入死迴圈。
為了避免死迴圈,我們可以不右移輸入的數字i。首先i和1做與運算,判斷i的最低位是不是為1。接著把1左移一位得到2,再和i做與運算,就能判斷i的次高位是不是1……這樣反覆左移,每次都能判斷i的其中一位是不是1。

 1 int NumberOf1_Solution2(int i)
 2 {
 3     int count = 0;
 4     unsigned int flag = 1;
 5     while(flag)
 6     {
 7         if(i & flag)
 8             count ++;
 9 
10         flag = flag << 1;
11     }
12     return count;
13 }

3 另外一種思路是如果一個整數不為0,那麼這個整數至少有一位是1。如果我們把這個整數減去1,那麼原來處在整數最右邊的1就會變成0,原來在1後面的所有的0都會變成1。其餘的所有位將不受到影響。舉個例子:一個二進位制數1100,從右邊數起的第三位是處於最右邊的一個1。減去1後,第三位變成0,它後面的兩位0變成1,而前面的1保持不變,因此得到結果是1011。
我們發現減1的結果是把從最右邊一個1開始的所有位都取反了。這個時候如果我們再把原來的整數和減去1之後的結果做與運算,從原來整數最右邊一個1那一位開始所有位都會變成0。如1100&1011=1000。也就是說,把一個整數減去1,再和原整數做與運算,會把該整數最右邊一個1變成0。那麼一個整數的二進位制有多少個1,就可以進行多少次這樣的操作。

比如

1100
1011
1000

1101
1100
1100

每次去掉最右邊的一個1

1int NumberOf1_Solution3(int i)
2 {
3 int count=0;
4 while (i)
5 {
6 ++ count;
7 i = (i-1)& i;
8 }
9 
10 return count;
11 }