1、判断一个二进制数中有多少个1
思路1:时间复杂度为O(二进制数长度)。判断最右一位是否为1并赋值"num+=v&0x0x",数右移一位"v>>1",循环直到数为0。
思路2:时间复杂度为O(二进制数中1个数)
将二进制数中最右的1置0,v = v&(v-1), num++,循环直到数为0
int count(int v){
int num = 0;
while(v){
v &= (v-1);
num++;
}
return num;
}
该思路在于(v-1)是将数中最右的1所在位变成0,然后用与运算消除后面产生的1,达到只将最右的1置0的效果。
2、函数Rand5()随机产生1、2、3、4、5中的一个数,且机率相等,基于该函数如何写出函数Rand7(),即随机产生1~7且机率相同
由于Rand5()只是产生离散数1~5,如果只调用一次Rand5()再进行变换,每个数产生的机率仍是1/5,因此该问题的核心在于找出七种不同且出现机率相同的数。
调用N次Rand5()方法,将出现5^N种有序排序,如果直接加减乘除则产生机率不同的数,即使拼凑也难以控制机率相同,因此最好保证5^N种有序排序通过某种运算结果还是5^N种、机率必然相同。而且,5^N个数肯定无法被7整除,因此某些情况出现一定会被踢出,并再次调用Rand7()。
以N=2为例,即调用2次Rand5(),将两次结果加起来,为了保证运算结果还是5^N种、出现机率相同,将第一次运行结果乘以10,即:x
= 10*Rand5() + Rand5()。
x等机率随机出现(11、12、13、14、15、21、....、25、31、...、35、41、...、45、51、...55)之一,总共25个数。要等机率出现1~7,选择前21种情况对应,出现后面4种情况出现后重新调用Rand5()。可采用switch语句判断x = 10*Rand5() + Rand5()实现程序。更好的,我们可以考虑,为了让x连续,即选择
x = 5*(Rand5() - 1)+ Rand5()
x等机率随机出现(1、2、3、...、25)之一,返回时就不用switch语句判断,而是返回(x-1)/3+1。
后面剔除的4种情况出现概率为16%,每次出现后都要再进行上述操作,可以改变N算出最好的概率。
文献http://www.cricode.com/2456.html讲的不错。
3、给定三个数,如何组合三个数使产生的新数最大,(例58、52、5可组合成58525、58552、52585、....,其中58552最大)
思路:每两个数比较的时候,将两个数补成相同长度,补齐策略是补上数左边相同部分
代码如下:
import java.util.*;
public class MyCode2{
public static void main(String[] args){
Scanner sc = new Scanner(System.in);
int n1 = sc.nextInt();
int n2 = sc.nextInt();
int n3 = sc.nextInt();
sc.close();
if(isBigger(n1,n2)){
if(isBigger(n1,n3))
if(isBigger(n2,n3))
System.out.println(n1+","+n2+","+n3);
else
System.out.println(n1+","+n3+","+n2);
else
System.out.println(n3+","+n1+","+n2);
}
else{
if(isBigger(n1,n3))
System.out.println(n2+","+n1+","+n3);
else{
if(isBigger(n2,n3))
System.out.println(n2+","+n3+","+n1);
else
System.out.println(n3+","+n2+","+n1);
}
}
}
public static boolean isBigger(int a, int b){
boolean rst = false;
LinkedList<Integer> A = new LinkedList<Integer>();
LinkedList<Integer> B = new LinkedList<Integer>();
LinkedList<Integer> temp = new LinkedList<Integer>();
while(a>0){
A.add(a%10);
a = a/10;
}
while(b>0){
B.add(b%10);
b = b/10;
}
int len = A.size()>B.size()?A.size():B.size();
for(int i=0;i<len;i++){
//System.out.println(i+" "+A.getLast()+" "+B.getLast());
if(A.getLast()>B.getLast()){
rst = true;
break;
}else if(A.getLast()<B.getLast()){
rst = false;
break;
}
else if(A.getLast()==B.getLast()){
temp.addFirst(A.getLast());
A.removeLast();
B.removeLast();
}
if(A.isEmpty()){
A = temp;
}
if(B.isEmpty()){
B = temp;
}
}
return rst;
}
}
示例:
输入:1 2 3 输出: 3,2, 1
输入:58 52 5 输出:58,5, 52
输入:5250 52 6 输出: 6,52,5250
4、商标上的字符串打印后发现字符‘g’和‘9’很难分清,现需采用手段进行补救,首先需找出所有可能产生的字符串,例如“99”,可能被认为是“99”、“9g“、“g9”、“gg”。
若字符串中字符‘g’和‘9’的总个数是n,则可能产生2^n种情况,并且可以发现其与二进制数有某种相似之处,因此直接将二进制中的‘0’、‘1’与‘g’和‘9’替换即可。代码如下:
import java.util.*;
public class CodeOne{
public static void main(String[] args){
Scanner sc = new Scanner(System.in);
String str = sc.nextLine();
sc.close();
ArrayList<Integer> al = new ArrayList<Integer>();
for(int i=0;i<str.length();i++){
char ch = str.charAt(i);
if(ch=='9'||ch=='g')
al.add(i);
}
int N = (int)Math.pow(2, al.size());
for(int j=0;j<N;j++){
StringBuffer sbur = new StringBuffer(str);
//转换成二进制字符串并补齐
String binstr = Integer.toBinaryString(j);
while(binstr.length()<al.size()){
binstr = "0"+binstr;
}
System.out.println(binstr);
//二进制与字符替换
for(int k=0;k<al.size();k++){
if(binstr.charAt(k)=='0')
sbur.setCharAt(al.get(k), '9');
else if(binstr.charAt(k)=='1')
sbur.setCharAt(al.get(k), 'g');
}
System.out.println(sbur);
}
}
}
示例:
输入:99 输出:99、9g、g9、gg
输入:0129g 输出:01299、0129g、012g9、012gg
前3道是2016年携程机试与面试题,第4道是2016年网易机试题。