现有n个人围坐一圈,顺时针给大家编号,第一个人编号为1,然后顺时针开始报数。第一轮依次报1,2,1,2...没报1的人出局。接着第二轮再从上一轮最后一个报数的人开始依次报1,2,3,1,2,3...没报1的人都出局。以此类推直到剩下以后一个人。现给定一个int n,要求返回最后一个人的编号。
测试样例:
5
返回:5
自己遇到了的坑: 1.开始用了ArrayList,结果没有addFirst()方法,于是用add(index,Obiect) 的方法添加到表头,实际上只添加到index-1后。 2.在遍历链表删除报数非1的过程中,不敢在判断报数非1后直接调用remove()方法,感觉 会破坏后面的顺序,采用了比较笨的方法,改变值为-1,下一次遍历的时候根据值来删除 import java.util.*; public class Joseph { public int getResult(int n) { // write code here /* 新建一个链表,依次将1-n添加到列表中(存储每个值得索引)*/ LinkedList<Integer> list=new LinkedList<Integer>(); for(int i=1;i<n+1;i++) { list.add(i); } /* 报数时的初始步长*/ int origenStep=2; /* 遍历链表,直到只剩一个元素时退出 */ while(list.size()>1) { /* 模拟报数,将报数过程中与origenStep取余值非1的值设为-1,方便后面删除*/ for(int i=0;i<list.size();i++) { if((i+1)%origenStep!=1) { list.set(i,-1); } } /*报数最大值加1*/ origenStep++; /*再一次遍历链表,将值为-1的对象删除,得到报数一遍后的剩余队伍*/ Iterator<Integer> iter=list.iterator(); while(iter.hasNext()) { if(iter.next()==-1) { iter.remove(); } } /* 去队伍的最后一个人,加入链表头,模拟从最后一个人开始*/ list.addFirst(list.get(list.size()-1)); /* 删除最后一个元素(已经加入表头中)*、 list.remove(list.size()-1); } /*返回链表的第一个元素值*/ int num=list.get(0); return num; } }
public static int getResult(int n) { // write code here if (n < 1) { return -1; } LinkedList<Integer> idList = new LinkedList<>(); for(int i = 1; i <= n; i += 2){//第一轮偶数全都出局,所以初始化列表只需要奇数就行 idList.add(i); } int j = 3;//第二轮开始就是报三个数了 while(j <= n){ idList.addFirst(idList.removeLast());//尾部移动到头部 int len = idList.size(); int k = 1; for(int i = 1; i <= len; i++){//删除时注意列表是在不停缩短的 if (i % j != 1) { idList.remove(i - k); k++; } } if(idList.size() <= j){ return idList.getLast(); } j++; } return 1; }
//list int getResult(int n){ list<int>A; for(int i=1;i<=n;++i)A.push_back(i); int index,cnt = 2; while(A.size()>1){ index = 0; auto it = A.begin(); while(it != A.end()){ index = (index + 1)%cnt; if(index!=1)it = A.erase(it); else it++; } A.push_front(A.back()); A.pop_back(); ++cnt; } return A.back(); } //vector int getResult(int n) { vector<int>A; for(int i=1;i<=n;++i)A.push_back(i); int index,cnt = 2; while(A.size()>1){ index = 0; for(int i=0;i<A.size();){ index = (index+1)%cnt; if(index != 1)A.erase(A.begin()+i); else ++i; } A.insert(A.begin(),A.back()); A.pop_back(); cnt++; } return A[0]; }
#用字典来解决约瑟夫问题
public int getResult(int n) { // write code here if(n<=2){ return 1; } LinkedList<Integer> list = new LinkedList<>(); for(int i = 1;i<=n;i+=2){//第一轮 先淘汰掉偶数 剩下全是奇数 list.add(i); } int count = 3; while(count<=n){ int last = list.removeLast(); list.addFirst(last); int k = 1;//这个k用的比较好 int len = list.size();//保留原来列表长度 for(int i = 1;i<=len;i++){//接下来列表长度是在变化的 if(i%count!=1){ list.remove(i-k); k++;//所以删除一个元素就让k加1,因为删除元素后面的元素都进行了前移,这样下次再删除时能够删除正确元素 } } if(count>=list.size()){ return list.getLast(); } count++; } return 1;//这个其实就是为了编译通过,根本不会走到这一步的 }
class Joseph { public: int getResult(int n) { if (n <= 2) return 1; n >>= 1; vector<int> people(n + 1); for (int i = 0; i <= n; ++i) people[i] = 1 + (i << 1); int last = n; int m = 3; while (people.size() > 1) { vector<int> pre, post; int curNum = 1; post.emplace_back(people[last]); for (int i = last + 1; i < people.size(); ++i) { ++curNum; if (curNum == m + 1) curNum = 1; if (curNum == 1) post.emplace_back(people[i]); } for (int i = 0; i < last; ++i) { ++curNum; if (curNum == m + 1) curNum = 1; if (curNum == 1) pre.emplace_back(people[i]); } last = pre.size() - 1; pre.insert(pre.end(),post.begin(), post.end()); swap(pre, people); ++m; } return people[0]; } };
public int getResult(int n) { Node head, t, p; //p记录上一个节点,t是临时节点 p = head = t = new Node(1); for (int i = 2; i <= n; i++, t = t.next) { t.next = new Node(i); } t.next = head; // 构成环 for (int k = 2; n != 1; k++) { //k代表级数,当只有一个节点时跳出循环 t = p; final int size = n; for (int i = 1, cnt = 1; i <= size; i++, cnt++, t = t.next) { //cnt计数, size代表一圈的Node个数 if (cnt == 1) { p = t; continue; } if (cnt == k) cnt = 0; p.next = t.next; n--; } } return t.val; } static class Node { int val; Node next; public Node(int val) { this.val = val; } }
class Joseph { public: int getResult(int n) { list<int> l; for(int i = 1; i <= n; ++i) l.push_back(i); for(int i = 2; i < INT_MAX; ++i) { if(l.size() == 1) break; int j = 1; for(auto itr = l.begin(); itr != l.end(); ++j) { if(j % i != 1) l.erase(itr++); else ++itr; } l.push_front(l.back()); l.pop_back(); } return l.front(); } };
int getResult(int n) { vector<int>a(n, 0); for (int i = 0; i < n; i++) a[i] = i+1; vector<int>b; int num = 2; while (a.size() != 1) { for (int i = 0; i < a.size(); i++) { if ((i+1) % num == 1) { b.push_back(a[i]); } } int tmp = b[b.size() - 1]; b.pop_back(); a = b; a.insert(a.begin(), tmp); b.clear(); num++; } return a[0]; // write code here }
/** * 核心数据结构:双链表 */ public int getResult(int n) { if (n < 1) return -1; LinkedList<Integer> list = new LinkedList<Integer>(); int round = 2, i, curr = 0; for (i = 1; i <= n; i++) { list.add(i); } while (list.size() > 1) { i = 0; while (list.size() > 1 && i < list.size()) { curr = (curr + 1) % round; if (curr != 1) { list.remove(i); } else { i++; } } round++;// 下一轮的最大报数 curr = 0;// 表示还未开始报数 if (list.size() > 1) {// 将最后报数的元素移动到链表首部,即确保每次报数从链表首部开始。 int last = list.removeLast(); list.addFirst(last); } } return list.pop();// 返回最后一个元素 }
import java.util.*; public class Joseph { public int getResult(int n) { return ysf(n, 2); } public int ysf(int n, int m) { int tmp = n%m==0 ? n/m : n/m+1; if(tmp <= m+1) { return (tmp-1)*m+1; //终止条件 } int path = ysf(tmp, m+1); //m+1次时最后一人编号的位置 return (path-2)*m + 1; } }
class Joseph { public: int getResult(int n) { // write code here vector<int> joseph; for (int i = 1; i <= n; i++) { joseph.push_back(i); // 生成joseph数组 } int m = 2; // 起始间隔 while (joseph.size() != 1) { // 直到只有一个元素为止 vector<int> tmp; tmp.push_back(0); // 先放一个元素进去,避免第2步头插数组整体后移 for (size_t i = 1; i <= joseph.size(); i += m) { tmp.push_back(joseph[i - 1]); // 把要保留的元素取出来 } tmp[0] = tmp.back();// 第2步,把最后一个元素放在第一位置 tmp.erase(tmp.end() - 1);// 去掉最后一个元素 joseph.swap(tmp); // 交换 m++; // 间隔增1 } return joseph.back(); // 返回唯一的元素 } };
# -*- coding:utf-8 -*- class Joseph: def getResult(self, n): if n <= 0: return -1 con = range(1, n + 1) rest = n round = 1 while con: start = 1 for key, person in enumerate(con): if start == round + 2: start = 1 if start != 1: rest -= 1 con[key] = -1 start += 1 con = [i for i in con if i != -1] if rest == 1: return con[0] con.insert(0, con.pop()) round += 1
/* 思路: 以n=5举例: 1 2 3 4 5 遍历第1次 1 2 1 2 1 1 3 5 遍历第2次 2 3 1 ==>5 (1)每次遍历的个数不同,用两个变量控制 count计数器,len更新每次链表长度 (2)三个迭代器控制删除,起始位置 cur:当前位置 next:链表删除会使cur失效,next用来记忆cur位置 last:用来更新每次遍历的初始位置 */ class Joseph { public: int getResult(int n) { // write code here list<int> circle; for (int i = 1; i <= n; i++) { circle.push_back(i); } list<int>::iterator cur, next, last = circle.begin(); int count, len, m = 1; while (circle.size() > 1) { len = circle.size(); count = 1; m++; cur = last; while (count <= len) //遍历1次 { for (int i = 0; i < m; i++) { next=++cur; if (next == circle.end()) next = circle.begin(); cur--; if (i != 0) circle.erase(cur); else last = cur; cur = next; count++; if (count > len) break; //if (count >= len) error!!! } } } return circle.front(); } };
class Joseph { public: int getResult(int n) { // write code here return helper(n,2)+1; //换一种编号策略,从0开始,这样方便计算,所以返回结果时加1 } int helper(int n,int c){ if(n<=c)return 0; //int left=n/c+(!!(n%c)); int left=(n-1)/c+1;//计算剩余人数 return (helper(left,c+1)+left-1)%left*c; //先把剩余人数看做从最后一个开始的0到left-1编号,递归返回后寻找与原始编号的关系 } };