您好我遇到了这个问题并试图解决这个问题
花一点时间想象你在一个有100把椅子排成一个圆圈的房间里。这些椅子按顺序编号从一到一百。 在某个时间点,#1椅子上的人将被告知要离开房间。将跳过椅子#2中的人,并且将告知椅子#3中的人员离开。旁边去的是椅子#6的人。换句话说,最初会跳过1个人,然后是2,3,4 ......等等。这种跳绳模式将继续围绕圈子,直到只剩下一个人......幸存者。请注意,当人离开房间时,椅子会被移除。写一个程序来确定幸存者所在的椅子。
我取得了很好的进展但坚持了一个问题,在计数达到100并且不确定如何从这里进行迭代之后,任何人都可以帮助我,这是我的代码
import java.util.ArrayList;
public class FindSurvivor {
public static void main(String[] args) {
System.out.println(getSurvivorNumber(10));
}
private static int getSurvivorNumber(int numChairs) {
// Handle bad input
if (numChairs < 1) {
return -1;
}
// Populate chair array list
ArrayList<Integer> chairs = new ArrayList<Integer>();
for (int i = 0; i < numChairs; i++) {
chairs.add(i + 1);
}
int chairIndex = 0;
int lr =0;
while (chairs.size() > 1) {
chairs.remove(lr);
chairIndex+=1;
System.out.println(lr+" lr, size "+chairs.size()+" index "+chairIndex);
if(lr==chairs.size()||lr==chairs.size()-1)
lr=0;
lr = lr+chairIndex;
printChair(chairs);
System.out.println();
}
return chairs.get(0);
}
public static void printChair(ArrayList<Integer> chairs){
for(int i : chairs){
System.out.print(i);
}
}
}
答案 0 :(得分:2)
答案是31.这里有三种不同的实现
var lastSurvivor = function(skip, count, chairs) {
//base case checks to see if there is a lone survivor
if (chairs.length === 1)
return chairs[0];
//remove chairs when they are left/become dead
chairs.splice(skip, 1);
//increment the skip count so we know which chair
//to leave next.
skip = (skip + 1 + count) % chairs.length;
count++;
//recursive call
return lastSurvivor(skip, count, chairs);
};
/** TESTS *******************************************************************
----------------------------------------------------------------------------*/
var result = lastSurvivor(0, 0, chairs);
console.log('The lone survivor is located in chair #', result);
// The lone survivor is located in chair # 31
/** ALTERNATE IMPLEMENTATIONS ***********************************************
-----------------------------------------------------------------------------
/* Implemenation 2
-----------------*/
var lastSurvivor2 = function(chairs, skip) {
skip++;
if (chairs === 1)
return 1;
else
return ((lastSurvivor2(chairs - 1, skip) + skip - 1) % chairs) + 1;
};
/** Tests 2 *******************************************************************/
var result = lastSurvivor2(100, 0);
console.log('The lone survivor is located in chair #', result);
// The lone survivor is located in chair # 31
/* Implemenation 3
------------------*/
var chairs2 = [];
for (var i = 1; i <= 100; i++)
chairs2.push(i);
var lastSurvivor3 = function(chairs, skip) {
var count = 0;
while (chairs.length > 1) {
chairs.splice(skip, 1);
skip = (skip + 1 + count) % chairs.length;
count++;
}
return chairs[0];
};
/** Tests 3 *******************************************************************/
var result = lastSurvivor3(chairs2, 0);
console.log('The lone survivor is located in chair #', result);
// The lone survivor is located in chair # 31
答案 1 :(得分:0)
我不确定您的删除模式是什么,但我可能会将其作为圆形链表实现,其中第100个座位支架将连接回第一个座位支架。如果您使用阵列,则必须担心每次移除后重新组织座位。
答案 2 :(得分:0)
如果您的步骤是增量步骤,则可以使用以下代码:
int cur = 0;
int step = 1;
while (chairs.size() > 1) {
chairs.remove(cur);
cur += ++step;
cur %= chairs.size();
}
return chairs.get(0);
如果您的步骤固定为1,那么根据@Jarlax提供的解释,您可以在O(log n)时间内使用一行代码解决问题:
//for long values
public static long remaining(long numChairs) {
return (numChairs << 1) - (long)Math.pow(2,Long.SIZE - Long.numberOfLeadingZeros(numChairs));
}
//for BigInteger values
public static BigInteger remaining(BigInteger numChairs) {
return numChairs.shiftLeft(1).subtract(new BigInteger("2").pow(numChairs.bitLength()));
}
但是,如果您坚持使用ArrayLists,则代码不需要额外的变量。始终删除第一个元素,然后删除 - 然后添加列表末尾的下一个元素。然而,这是O(n)。
while (chairs.size() > 1) {
chairs.remove(0);
chairs.add(chairs.remove(0));
}
return chairs.get(0);
答案 3 :(得分:0)
有优雅的分析解决方案:
让我们改变人数:#2 - &gt; #1,#3 - &gt; #2,...,#1 - &gt; #100(最后我们只需要将1减去&#34;修复&#34;结果)。现在第一个人保持相反或离开。假设圈中只有64个人。很容易看出,在第一次淘汰后,圈中的32个人将保留,编号将从#1开始。所以最终只剩下#1。
我们有100个人。在36人离开这个圈子之后我们最终会有64个人 - 我们知道如何解决这个问题。对于离开房间的每个人,一个人仍然存在,所以64人的圈子将从1 + 2 * 36 =#73(新#1)开始。由于在第一步改变索引,最终答案将是#72。
一般情况下,res = 2 *(N - nearest_smaller_pow_2)= 2 * N - nearest_larger_pow_2。代码很简单:
public static long remaining(long total) {
long pow2 = 1;
while (pow2 < total) {
pow2 *= 2;
}
return 2*total - pow2;
}
此算法也具有O(log(N))复杂度而不是O(N),因此可以计算巨大输入的函数(它可以很容易地适应使用BigInteger而不是long)。 / p>
答案 4 :(得分:0)
首先,让我们假设椅子从0开始编号。我们将在最后切换编号 - 但是当项目从0而不是1枚举时,通常情况会更简单。
现在,如果你有n个人并且你开始在椅子x上消除(x是0或1),那么在一次通过你就会消灭一半的人。然后你有一个大约一半大小的问题(可能加一个),如果你解决了这个问题,你可以通过将该子结果乘以2并可能加一个来构造原始问题的解决方案。
要对此进行编码,只需将4个案例(n个奇数或偶数对x 0或1)设为正确。这是一个通过使用按位技巧获得4个案例的版本。
public static long j2(long n, long x) {
if (n == 1) return 0;
return j2(n/2 + (n&x), (n&1)^x) + 1-x;
}
现在可以编写一个编号从1开始并且没有额外参数的解决方案:
public static long remaining(long n) {
return 1 + j2(n, 0);
}
这在O(log n)时间运行并使用O(log n)内存。