剑指Offer
圆圈中最后剩下的数
微众笔试
n人围成一圈,每次报到m的人淘汰
数组实现
int i = -1, j = n;
int[] a = new int[n];
while(j>1){
for(int k=0; k<m;){
i++;
if(i == n)
i = 0;
if(a[i] == 0) k++;//有效位才k++
}
a[i] = 1; j--;
}
for(int x=0; x<n; x++){
if(a[x] == 0)
return x;
}
return -1;
这种写法是模仿剑O里while…for if,remove…return 的结构写的,数组用1代表被删除,这样做最后需要for循环判断哪个位为0,因为实际上并没有真正删除元素。
链表实现
首先Java的迭代器
Iterator<Integer> iter = list.iterator();
剑指Offer中C++的迭代器写起来比较麻烦,Java版如下(网上有个用LinkedList.get(Index)方法的版本,面试这么写直接暴露自己链表都不懂)
LinkedList<Integer> list = new LinkedList<>();
for (int i = 0; i < n; i++) {
list.add(i);
}
Iterator<Integer> current = list.iterator();
while(list.size()>1){
for(int i = 0; i<m; i++){
if(!current.hasNext())//和.end()的判断是不同的,要放在next前面
current = list.iterator();
current.next();
}
current.remove();
}
return list.getFirst();
之所以会比c++简单,是因为java迭代器的是位于两个元素之间的性质。
注意 if 不能放在current.next()之后,否则会在链表开头调用remove,(出现IllegalStateException)另外在链表末尾调用next()会出现NoSuchElementException,所以最后return不要用迭代器的next();
本题的结构是 while…for if,remove…return;
获取链表的开端,numbers.begin(),Java用 list.Iterator()。
创新的解法
f(n) = [f(n-1)+m]%n
public int LastRemaining(int n) {
if(n<1||m<1) return -1;
int last = 0;
for(int i=2;i<=n;i++){
last = (last+m)%i;
}
return last;
}
这主要记住公式,last = (last+m)%i,结构是 for……return