晚上有群友出题:
abcdefghijklmnopqrs循环106次,组成新的2014个字符的字符串,然后删掉奇数位的字符,再次组成新的字符,在删掉奇数字符,最后剩下一个字符,这个字符是啥
先用笨办法,模拟每一次删除操作,直到只剩下最后一个值
第一个元素的索引是0,本来应该依次删除 2,但是删了0之后,所有的位置都往前移了一位,所以接下来要删除的索引是1。所以i只需要自增1。
import java.util.*;
public class Test {
public static void main(String[] args){
List<Character> list = new ArrayList<Character>();
String s = "abcdefghijklmnopqrs";
for(int i = 1; i <= 106; i++){
for(int j = 0; j < s.length(); j++){
list.add(s.charAt(j));
}
}
long start = System.nanoTime();
while(list.size() > 1){
for(int i = 0; i < list.size(); i++){
list.remove(i);
}
}
System.out.println("用时:" + (System.nanoTime() - start) + "纳秒");
System.out.println(list.get(0));
}
}
------Output------
用时:1711791纳秒
q
上面是最笨的办法,List的查找和删除消耗了大量时间。改进了一下思路:
原始的索引是:
0 1 2 3 4 5 6 7 8 9 10 11 12.......
删了一次后,索引是:
1 3 5 7 9 11 13 15 17 19...........
再删,索引是:
3 7 11 15 19.....
继续删,索引是:
7 15 .....
当删得只剩下一个数时,是最终结果。而这个唯一的数,同时也是剩下的第一个数,所以可以找第一个数的索引有什么规律。
0*2+1=1,1*2+1=3,3*2+1=7....
这样一直找下去,直到找出最后一个小于2014的值,就是最后剩下的索引值。
public class T3{
public static void main(String[] args){
String s = "abcdefghijklmnopqrs";
StringBuilder sb = new StringBuilder();
for(int i = 1; i <= 106; i++){
sb.append(s);
}
//下面开始查找
long start = System.nanoTime();
int t = 0;
while((t*2+1)<= 2014){
t = t*2+1;
}
System.out.println((System.nanoTime()-start) + "纳秒");
System.out.println(sb.charAt(t));
}
}
------Output------
3421纳秒
q
做完又百度了一下,发现有位大神更牛:
就是第1024位置的字母"q" 第一次留下的是2的倍数,第二次留下的是4的倍数,第三次就是8的倍数。 代码的话,只要一句话。 return ('a' + 1024%19-1);
这位大神的想法前半部分和我是一样的,只是他从1开始编号,而我从0开始编号。后面取出字母的方法更简单直接,佩服。