前几天在牛客上做了一道编程题,题目是这样的:
对于一个正整数,我们认为它的光棍指数是它二进制表示下1的个数。
通常认为光棍指数越高,这个数就越孤单。那么问题来了,对于给定的[a,b]区间中。最孤单的数字是谁呢?
通常认为光棍指数越高,这个数就越孤单。那么问题来了,对于给定的[a,b]区间中。最孤单的数字是谁呢?
如果光棍指数相同,最孤单的就是最小的那个数。
后来百度了一下,发现这道题的原形是前几年微软的一道面试题(http://www.cnblogs.com/fangyukuan/archive/2010/09/18/1829871.html),只不过做了变形。然后根据这道题用Java写了出来。最后发现通过率只有50%,郁闷了。
代码如下:
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Scanner;
/**
* 对于一个正整数,我们认为它的光棍指数是它二进制表示下1的个数。
通常认为光棍指数越高,这个数就越孤单。那么问题来了,对于给定的[a,b]区间中。最孤单的数字是谁呢?
如果光棍指数相同,最孤单的就是最小的那个数。
* @author Tony
*
*/
public class GuangGun {
public static int maxNum = 0;
public static void main(String[] args) {
List<String> issueList = new ArrayList<String>();
Scanner scanner = new Scanner(System.in);
while(scanner.hasNextLine()) {
issueList.add(scanner.nextLine());
}
for(int i=1; i<issueList.size(); i++) {
Map<Integer, Integer> map = new HashMap<Integer, Integer>();
String parts[] = issueList.get(i).split("\\s+");
int min = Integer.parseInt(parts[0]);
int max = Integer.parseInt(parts[1]);
if(min > max) {
System.out.println("input error");
} else {
for(int j=min; j<=max; j++) {
int countx = fun(j);
if(countx > maxNum) {
maxNum = countx;
map.clear();
map.put(maxNum, j);
}
}
}
System.out.println("Case " + i + ": " + map.get(maxNum));
maxNum = 0;
}
}
private static int fun(int x) {
int countx = 0;
while(x > 0) {
countx ++;
x = x&(x-1);
}
return countx;
}
}
结合这道题,顺便复习下逻辑运算:
1.位异或运算(^)
运算规则是:两个数转为二进制,然后从高位开始比较,如果相同则为0,不相同则为1。
2.位与运算符(&)
运算规则:两个数都转为二进制,然后从高位开始比较,如果两个数都为1则为1,否则为0。
3.位或运算符(|)
运算规则:两个数都转为二进制,然后从高位开始比较,两个数只要有一个为1则为1,否则就为0。
4.位非运算符(~)
运算规则:如果位为0,结果是1,如果位为1,结果是0.
本题的神奇之处在于这算法:
private static int fun(int x) {
int countx = 0;
while(x > 0) {
countx ++;
x = x&(x-1);
}
return countx;
}
为什么最后countx为这个数二进制中1的个数,还是一脸懵比。