題目:

這個題做到最后,時間不是很夠,題目內容比較簡單,求出第k個正整數符合x+y=x|y,然而這個k的取值范圍非常大(k<=2000000000),所以可以不用考慮窮舉法,當然,時間不夠的話寫個窮舉試試運氣也可以。
窮舉法:
1 import java.util.Scanner; 2 3 /** 4 * Created by Administrator on 2016/9/6. 5 */ 6 7 public class Main { 8 public static void main(String[] args) { 9 Scanner scanner = new Scanner(System.in); 10 int x = scanner.nextInt(); 11 int k = scanner.nextInt(); 12 int n = 0; 13 int result = 0; 14 for (int i = 1; i <= 2000000000; i++) { 15 if ((x + i) == (x | i)) { 16 n += 1; 17 } 18 if (n == k) { 19 result = i; 20 break; 21 } 22 } 23 System.out.println(result); 24 } 25 }
這里提交會提示超時,所以這個算法是不行的,比較循環的次數太多。
第一個想法是能不能減少循環次數,但是考慮到要求第k個,也就是不能省略掉其中一些否則會遺漏,所以只能考慮能否不使用循環求得。
因為這里用到了位運算,所以可以通過二進制來演算一下。
假設數據x=5,k=1的時候,y=2,分別用二進制進行表示:
5D = 0101B
2D = 0010B
7D = 0111B
這里其實已經可以發現規律了。
x+y是把x和y每一個二進制位進行相加,1+1就進位
x|y則是每個二進制位置對應的進行或運算(有1得1)
這個題目中,x的值是固定的,也就是x的二進制數中1的位置和數目是固定的,所以進行或運算的時候,結果中對應的位上都應該是1。
現在考慮相加的情況,假設y與x中某一對應的位置都是1,就需要進行進位,也就是這個位置會變成0,顯然x+y!=x|y。
考慮x中0的影響,因為在相加或者或運算的時候,0都不會影響到運算結果,所以結論很顯然:
yB的對應於xB上所有為1的位均為0,則必有x+y=x|y。
現在考慮如何得到第k個。
因為有上面的規律,我們可以得知,y中為1的位只能對應於x中為0的位。
這里就很簡單了,我們只需要求出k的二進制值,並且把這個二進制的值從低位逐個填入x為0的位即可得到相加的結果。
如:5+2=5|2=7 k=1
5D = 0101B
1D = 0001B
我們把1的二進制填入至x的二進制為0的地方則能得到0111B,也就是十進制的7。7-5=2,就能得到y的值。
再舉一個例子:x=5, k=2
5D = 0101B
2D = 0010B

把2的二進制從低位開始填入5的二進制數中為0的地方,即可得到1101B,也就是13,所以y=13-5=8。
實際上,我們只需要把x中對應為1的地方改為1,就能直接得到y的值,相當於減去x。
所以我們在實際構造的時候,可以這樣做:
逆序遍歷x的每一位
如果為1,則往結果的頭部填充一個0(減法)
否則將k中的最后一位填入結果的頭部,並退出k的最后一位,此時如果k已經為空,則退出遍歷。
判斷x是否已經遍歷完,如果是,將k剩余的位一次填充到結果的頭部。
AC代碼:
1 import java.util.Scanner; 2 3 /** 4 * Created by Administrator on 2016/9/6. 5 */ 6 7 public class Main { 8 public static void main(String[] args) { 9 Scanner scanner = new Scanner(System.in); 10 int x = scanner.nextInt(); 11 int k = scanner.nextInt(); 12 String x_str = Integer.toBinaryString(x); 13 String k_str = Integer.toBinaryString(k); 14 StringBuilder sb = new StringBuilder(); 15 int pointer = k_str.length() - 1; 16 for (int i = x_str.length() - 1; i >= 0; i--) { 17 if (x_str.charAt(i) == '1') { 18 sb.insert(0, "0"); 19 } else { 20 sb.insert(0, k_str.charAt(pointer)); 21 pointer -= 1; 22 if (pointer < 0) { 23 break; 24 } 25 } 26 if (i == 0 && pointer >= 0) { 27 sb.insert(0, k_str.substring(0, pointer + 1)); 28 } 29 } 30 System.out.println(Long.parseLong(sb.toString(), 2)); // 使用Long是因為結果可能會超過Integer的表示范圍 31 } 32 }
