Java面试-5道算法
笔试题还是遇到了算法题,我对于做答题从来不慌,就是算法题总是不够稳。今天是五道算法题,我一道一道的来讲解一下。题目由我个人简单描述
第一题:
丑数:判断一个数是否是一个丑数。丑数是指只有质因数2,3,5的正整数,包括自然数1。是丑数返回1,不是丑数返回0。
解析
我的思路是通过把这个数依次做判断,如果能被2整除,那就/2,如果能被3整除,那就/3,如果能被5整除,那就/5,如果都不行就不是丑数;把这个判断做循环,如果最后剩下来1,那么就是丑数
public int isUglyNumber(int num){
if(num<1)return 0;
if(num<7)return 1;
while(true){
if(num==1)return 1;
else{
if(num%2==0) num/=2;
else if(num%3==0) num/=3;
else if(num%5==0) num/=5;
else return 0;
}
}
}
网上搜了一下,其实可以直接while循环遍历,判断最后是不是剩下1
public boolean isUgly(int num)
{
if(num<=0) return false;
while(num%2==0) num/=2;
while(num%3==0) num/=3;
while(num%5==0) num/=5;
return (num==1);
}
第二题:
卡牌游戏:小三给小舞n张牌,分别是0到n-1,把他们按顺序从0-n-1排成环形,然后从0开始走,每三步抽掉一张牌,问最后留下哪一张卡牌,返回他的数字。
解析
我首先想到先用队列,发现放值取值复杂,单纯数组晒选应该可以,但都不是正统思路,其实他就是一个约瑟夫环的问题`,我用的是一个个计数,循序到0时重新开始从头遍历,如果去掉一张牌总共的牌数减一。直到只剩下一个人。
public static int josephus(int n, int m) {
//n个人, 0 1 2..n-1
int[] people = new int[n];
//人的索引
int index = -1;
//报数记录, 1 2 3..m
int count = 0;
//剩余人数 初始值为n
int remain = n;
//为了找到最后一个幸存者的位置,假设所有人都会被杀
while (remain > 0) {
index++; //找到报数的人
if (index == n) { //所有人遍历一圈后从头遍历
index = 0;
}
if (people[index] == -1) { //如果当前的人被杀 跳过
continue;
}
count++; //报数
if (count == m) {
people[index] = -1; //报数到m后杀人
count = 0; //报数重置
remain--; //剩余人数递减
}
}
return index;
}
上面这种计数过程比较浪费空间,用LinkedList双向链表实现思路更加清晰。
public static int cycle(int n){
List<Integer> dataList=new LinkedList<>();
for(int i=0;i<n;i++){
dataList.add(i+1);
}
int index=-1;
while(dataList.size()>1){
index=(index+3)%dataList.size();
dataList.remove(index--);
}
return dataList.get(0);
}
第三题:
进制转换:将一个进制为N的字符串转换成另一个进制为M的字符串
public static String changeRadix(String num,int N,int M){
Long i=Long.valueOf(num,N);
if(i<M){
if(i>9) return (char)(i+55)+"";
else return i+"";
}
return changeRadix(i/M+"",10,M)+changeRadix(i%M+"",10 ,M );
}
第四题:
Z字排列:将一个字符串按照指定行数line,像“N”字型排列,然后输入正常从左往右逐行读的字符串,空字符不读。
解析:
道题没什么可说的,不需要什么数据结构与算法的知识。给定一个字符串,换个花样输出。题目中所谓的"Z"字形变换,无非就包含两种操作,直接按题目要求模拟,先竖着往下读,然后斜上读,一直将字符串读完为止。
public String convert(String s, int numRows) {
if (numRows == 1) {
return s;
}
StringBuilder[] sbs = new StringBuilder[numRows];
for (int i = 0; i < numRows; i++) {
sbs[i] = new StringBuilder();
}
int index = 0;
while (index < s.length()) {
// "竖下"读取
for (int i = 0; i < numRows && index < s.length(); i++) { // 这里加index < s.length() 是防止在做"竖下"操作的时候字符串读完了,下面同理
sbs[i].append(s.charAt(index));
index++;
}
// "斜上"读取,从下往上读,最后一行和第一行是算在"竖下"读取中的,所以只存中间numRows - 2行
for (int i = numRows - 2; i > 0 && index < s.length(); i--) {
sbs[i].append(s.charAt(index));
index++;
}
}
// 将后面numRows-1行都拼接到第一行
for (int i = 1; i < numRows; i++) {
sbs[0].append(sbs[i]);
}
return sbs[0].toString();
}
第五题:
青蛙跳:从x轴0的位置开始跳,第一次跳一步,下一步比第一步多一步,每一步可以往正方向也可以往反方向,问你要几步到达给定目的地target。
解析:
这道题没做出来,之前也有一个类似的问题,他说可以跳坐标的任意倍数,问最短几步到达target。我不知道是按照递归还是什么思路,单个模拟也没有思路。现在还没想到怎么做,尖刀班的学生可以指点我一下。