已知n个人坐成一圈,按顺时针由1开始给大家编号。然后由第一个人开始顺时针循环报数,数到m的人出局,循环此过程直到最后只剩一个人。给定两个int n和m,要求编写函数返回最后一个人的编号。保证n和m小于等于1000。
class Joseph {
public:
int getResult(int n, int m) {
list<int> circle;
// 初始状况
for(int i = 1;i <= n;++i){
circle.push_back(i);
}//for
list<int>::iterator cur = circle.begin();
while(circle.size() > 1){
// 数到m的人出局
for(int i = 0;i < m - 1;++i){
++cur;
if(cur == circle.end()){
cur = circle.begin();
}//if
}// for
// 因为删除数到m的人要记录下一个人的地址
list<int>::iterator next = ++cur;
if(next == circle.end()){
next = circle.begin();
}//if
--cur;
// 删除数到m的人
circle.erase(cur);
// 从下一个人继续开始
cur = next;
}//while
return circle.front();
}
};
public int getResult(int n, int m)
{
// write code here
ArrayList<Integer> list = new ArrayList<>();
for (int i = 1; i < n + 1; i++)
list.add(i);
int r = 0;
while (list.size() > 1)
{
int k = (r + m) % list.size();
if (k == 0)
r = list.size() - 1;
else
r = k - 1;
list.remove(r);
}
return list.get(0);
}
import java.util.*;
/*
思路:因为本题的知识点是链表,因此想到可以用链表来做,至于数学方法,我真的不想用那个,第一我推不清楚,第二不符合题目考点吧
*/
public class Joseph {
public int getResult(int n, int m) {
LinkedList<Integer> list =new LinkedList<Integer>();
for(int i=1;i<=n;i++){
list.add(i);
}
int count=0;
while(list.size()>1){
int goal =(count+m-1)%list.size();
list.remove(goal);
count =goal%list.size();//这里要注意的,就是count!=goal/////count=goal%list.size(),因为前面删了一个,size变了,不过测试例子检查不出来
}
return list.get(0);
}
}
public int getResult(int n, int m) {
// write code here
/*
* 存在递推公式:
* f(n,m)表示n个人报数m的离开,最后留下来的人的初始号码
* f(n,m) = (f(n-1,m)+m)%n;
*/
if(n < 1 || m < 1){
return -1;
}
int last = 0;
if(n == 1){
return last;//最后一轮出局的人肯定是最后轮的第0个,要找到其初始号码
}
for(int i = 2; i <= n; i++){
last = (last + m) % i;//最后出来的人在倒数第i轮的号码是last
}
return last+1;//注意编号是1-n编号的,而算法是从0~n-1排序的
}
class Joseph {
public:
int getResult(int n, int m) {
// write code here
vector<int>a(n);
int j=0;
for(int i=0;i<n;i++)
a[i]=i+1;
for(int i=0;a.size()!=1;i=(++i)%a.size())
{
j++;
if(j==m)
{
j=0;
a.erase(a.begin()+i);
i--;
}
}
return a[0];
}
};
创建一个数组1、2、3...n;,每次删除一个元素,最后剩下的就是需要的结果 //链表
int getResult(int n, int m) {
ListNode *head = new ListNode(1),*p = head;
for(int i=2;i<=n;++i){
ListNode *node = new ListNode(i);
p->next = node;
p = p->next;
}
p->next = head;
while(p->next->val!=p->val){
int cnt = m;
while(--cnt){
p = p->next;
}
p->next = p->next->next;
}
return p->val;
} 思路:hh代码减了又减,这样我自己很满意了。我用vector(就是数组)来存放每个人 的编号,vector[0]=1,依次递增,数到m的元素删除,最后剩下的元素的值就是其最开 始的编号。p这个参数是上次删除的元素的位置。其实很好记: (m+p-1)%n 最简单的思路: 下面把第一次删除一个后的数组进行演示, (k+1,...,n-1,0,1,...k-1)转换为(0~n-2)的形式, k+1对应0 k+2对于1 ... k-1对应n-2 可以得到这样的递推关系式:x=(x+k+1)%n;这里的n是上一次的总人数,k=(m-1)%n; 所以从最后一个剩下的人开始推算,那么就是(last+m)%2;这里的“2”是因为倒数 第一次数数的时候还剩两个人。 class Joseph { public: int getResult(int n, int m) { vector<int> ya; for(int i=0;i<n;i++) ya.push_back(i+1); return Ysf(ya,n,m,0); } int Ysf(vector<int> &ya,int n,int m,int p) { if(n==1) return ya.front(); else { ya.erase(ya.begin()+(m+p-1)%n); return Ysf(ya,n-1,m,(m+p-1)%n); } } };
import java.util.*;
public class Joseph {
public int getResult(int n, int m) {
// write code here
if(n == 1) {
return 1;
}
LinkedList<Integer> list = new LinkedList<>();
for(int i = 1; i<= n; i++) {
list.add(i);
}
int index = 0;
while(list.size() != 1) {
index = (m + index - 1) % list.size();
list.remove(index);
}
return list.get(0);
}
}
//方法二:
import java.util.*;
public class Joseph {
public int getResult(int n, int m) {
if(n<=0||m<=0)
return -1;
int s=0;
for(int i=2;i<=n;i++)
s=(s+m)%i;
return s+1;
}
}
if(n<=0||m<=0)
return -1;
int s=0;
for(int i=2;i<=n;i++)
s=(s+m)%i;
return s+1;
渣渣用队列来做的 想不出递归 大神勿喷
class Joseph {
public:
int getResult(int n, int m) {
// write code here
queue<int> q;
int i = 1,j = m,k;
while(i <= n)
{
q.push(i);
i++;
}
while(q.size()>1)
{
while(j > 1)
{
k = q.front();
q.pop();
q.push(k);
j--;
}
q.pop();
j = m;
}
return q.front();
}
}; /*
* 使用链表真实模拟踢除过程即可
*/
import java.util.*;
public class Joseph {
public int getResult(int n, int m) {
// write code here
LinkedList<Integer> list = new LinkedList<Integer>();
for (int i = 1; i <= n; i ++) {
list.add(i);
}
int bt = 0;
while (list.size() > 1) {
int delPos = (bt + m - 1) % list.size();
list.remove(delPos);
bt = delPos % list.size();
}
return list.get(0);
}
}
使用了队列这个数据结构
class Joseph {
public:
int getResult(int n, int m) {
// write code here
queue<int> qu;
stack<int> st;
int count = 0, pNum = 0;
for (int i = 1; i <= n; i++) {
qu.push(i);
}
while (count != n) {
pNum++;
if (pNum != m) {
qu.push(qu.front());
qu.pop();
} else {
st.push(qu.front());
qu.pop();
pNum=0;
count++;
}
}
return st.top();
}
};
class Joseph {
public:
int getResult(int n, int m) {
// write code here
if(n<1||m<1)
return 0;
list<int>numbers;
for(int i=1;i<=n;++i)
numbers.push_back(i);
list<int>::iterator current=numbers.begin();
while(numbers.size()>1)
{
for(int i=1;i<m;++i)//向后移动m次
{
current++;
if(current==numbers.end())
current=numbers.begin();
}
//在删除current节点时要记录下current的下一个节点
list<int>::iterator next=++current;//这里不能写成current+1,因为只有顺序存储结构的迭代器才有加法操作
if(next==numbers.end())
next=numbers.begin();
numbers.erase(--current);
current=next;
}
return *current;
}
};
//用环形链表模拟圆圈,用list模拟环形链表
//list的底层是链表,vector的底层是数组,因此list在删除的时候要提前记录好待删除元素的下一个位置
//每次在对迭代器做完移动操作完之后都要判断迭代器是否走到了numbers的末尾,若走到了numbers的末尾,要把迭代器返回numbers的开始位置 import java.util.*;
public class Joseph {
public int getResult(int n, int m) {
//初始化队列
Queue<Integer> queue = new LinkedList<>();
//向队列中添加元素
for (int i=1; i<=n; i++){
queue.offer(i);
}
//判断队列的元素是否为1
while (queue.size() != 1){
//向队列尾部添加队列前m-1个元素,同时删除队列前m-1个元素
for (int i=1; i<m; i++){
queue.offer(queue.poll());
}
//删除队列第m个元素
queue.poll();
}
//如果队列只有1个元素,输出元素,不删除队列元素
return queue.peek();
}
} public int LastRemaining_Solution(int n, int m) {
if(m<=0)return -1;
ArrayList<Integer> child = new ArrayList<>();
for (int i = 0; i < n; i++) {
child.add(i);
}
int size=n;
int start=0;//下一轮索引开始位置
for(int i=0;i<size;i++){
if (n==1)break;
start=m%n-1==-1?(n-1 +start)%n:(m%n-1+start)%n;
System.out.println(child.get(start));
child.remove(start);
n--;
}
return child.get(0);
} int win = 1;
for (int _n=2; _n<=n; i++) {
win = (win + m) % _n;
if (win == 0) win = _n;
}
return win;
第一个删除的数字是(m-1)%n,几位k,则剩余的编号为(0,1,...,k-1,k+1,...,n-1),下次开始删除时,顺序为(k+1,...,n-1,0,1,...k-1)。
用f(n,m)表示从(0~n-1)开始删除后的最终结果。
用q(n-1,m)表示从(k+1,...,n-1,0,1,...k-1)开始删除后的最终结果。
则f(n,m)=q(n-1,m)。
下面把(k+1,...,n-1,0,1,...k-1)转换为(0~n-2)的形式,即
k+1对应0
k+2对于1
...
k-1对应n-2
转化函数设为p(x)=(x-k-1)%n, p(x)的你函数为p^(x)=(x+k+1)%n。
则f(n,m)=q(n-1,m)=p^(f(n-1,m))=(f(n-1,m)+k+1)%n,又因为k=(m-1)%n。
f(n,m)=(f(n-1,m)+m)%n;
最终的递推关系式为
f(1,m) = 0; (n=1)
f(n,m)=(f(n-1,m)+m)%n; (n>1)
代码如下
import java.util.*; public class Joseph { /* * 编号为(0~n-1) */ public int getResult(int n, int m) { if (n < 0 || m < 0) { return -1; } int last = 0; for(int i=2;i<=n;++i){ last = (last+m)%i; } // 因为实际编号为(1~n) return (last+1); } }