约瑟夫环问题: ?????????约瑟夫环(约瑟夫问题)是一个数学的应用问题:已知n个人(以编号1,2,3…n分别表示)围坐在一张圆桌周围。从编号为k的人开始报数,数到m的那个人出列;他的下一个人又从1开始报数,数到m的那个人又出列;依此规律重复下去,直到圆桌周围的人全部出列。通常解决这类问题时我们把编号从0~n-1,最后 结果+1即为原问题的解。 解法一:利用链表 ?????????我们可以把每一个人变成一个链表,然后不断地循环这个链表。每次删除一个结点,直到最终只剩下一个结点的时候就表示我们找到个!
class Node{
int val;
Node next;
public Node(int val){
this.val = val;
}
}
public int LastRemaining_Solution3(int n, int m) {
if(n == 0 || m == 0){
return -1;
}
Node head = new Node(0);
Node temp = head;
for(int i = 1 ; i < n ; i++){
temp.next = new Node(i);
temp = temp.next;
}
temp.next = head;
int index = 0;
while(head.next != head){
if(index == m-2){
head.next = head.next.next;
index = 0;
}
else{
index++;
}
head = head.next;
}
return head.val;
}
解法二:迭代 ?????????我们先举个例子~假设一共有5个人(n = 5),然后从0开始编号,从0开始报数,报到第2个出列(m = 3),我们来模拟一下这个过程。
0 1 2 3 4 (第一次出队的是2) 3 4 0 1 (第二次出队的是0) 1 3 4 (第三次出队的是4) 1 3 [ 1 3 ](第四次出队的是1) 3(最终剩余的是3)
?????????我们做这个题的时候只知道最后剩下的一定是一个数,他的下标是0,那我们可以从下往上看,根据下标找到最终的那个数。 ?????????所以我们需要看怎么从下面这一层的下标找到这个数在上一层的下标,我们发现当前下标加上m就是我们再上一层的下标,但是这个不一定是真实的下标,因为有可能我们当前的人数是小于m的,所以得到的下标就是一个将人数复制了之后的下标,那么想要得到真实的下标就是进行一个%操作就好,我们知道每次只出队1 个人,那么从后往前的人数分别是0,1,2…所以我们%一下这个人数就得到了真实的下标,然后再一样的办法,得到上一次循环该数的下标,直到到了最开始就知道我们这个最终剩下的人的下标,因为我们最开始的编号是从0开始的,所以回到最初的时候,下标就是编号,直接返回就好了! ?????????我们看这个图,红色的是每次要删除的数据,蓝色的是我们的到的下标,绿色的是真实的下标。我们最开始只知道最后一个3的下标是0,然后不断往上一层找,拿到3的下标。 代码:
public int LastRemaining_Solution(int n, int m) {
if(n == 0 || m == 0){
return -1;
}
int index = 0;
for(int i = 2 ; i <= n ; i++){
index = (index + m) % i;
}
return index;
}
还有的时候我们的是从1开始编号报数的,那么具体的代码是
public int LastRemaining_Solution2(int n, int m) {
if(n == 0 || m == 0){
return -1;
}
int index = 1;
for(int i = 2 ; i <= n ; i++){
index = (index + m) % i;
if(index == 0){
index += i;
}
}
return index;
}
?????????会比0开始的多一个步骤,但是思路完全一样~
|