ʚ自在飞花ɞ | 约瑟夫环的三种实现方式
题目链接
三种方式
- 第一种:在堆上构造链表并模拟删除过程
- 时间复杂度:
- 空间复杂度:
- 时间复杂度:
- 第二种:基于数组构造链表并模拟删除过程
- 时间复杂度:
- 空间复杂度:
- 时间复杂度:
- 第三种:递推公式
- 时间复杂度:
- 空间复杂度:
- 时间复杂度:
第一种:在堆上构造链表并模拟删除过程
这种方法是最直观的了。首先,定义如下结构体,用于存储链表。
struct Node {
Node(int v = 0) : val(v), next(nullptr) {}
int val; // 数据域
Node *next; // 指针域
}; 接着,通过尾插法构造链表。
此时,我们构造出了具备 n 个节点的链表。然后,我们将第 n 个节点的 next 指针指向第一个节点,这样就获得了一个环形链表。接下来,开始模拟删除过程。
单链表的删除操作也很简单:设待删除节点为 cur, 其前驱节点为 pre,即 pre->next 指向 cur。在单向链表中,通过修改 pre->next = cur->next 即可删除 cur 节点。
因为需要操作待删除节点的前驱节点,初始时不妨将 pre 指向第一个节点的前驱节点。这样才经过 m-1 次 pre=pre->next 的移动操作后,pre 的后继节点即为要删除的节点,此时通过修改 pre->next = pre->next->next 即可完成一次删除。
值得注意的是,在完成一次删除后,pre 恰巧仍指向下一轮游戏的第一个节点的前驱节点,也就是说,此时的 pre 仍然满足初始时位置要求。因此我们无需做任何调整,直接进行下一轮的 m-1 次移动操作和删除操作即可。
在经过 n-1 轮上述操作后,游戏结束,此时 pre 指向的节点即为答案。
下面为完整的代码实现,耗时 290ms。
class Solution {
public:
struct Node {
Node(int v = 0) : val(v), next(nullptr) {}
int val;
Node *next;
};
int ysf(int n, int m) {
Node dummy, *tail = &dummy;
for (int i = 1; i <= n; i++) {
tail->next = new Node(i);
tail = tail->next;
}
tail->next = dummy.next;
Node *pre = &dummy;
while(n > 1) {
for (int i = 1; i < m; i++, pre = pre->next) {}
auto tmp = pre->next;
pre->next = pre->next->next;
delete tmp;
n--;
}
return pre->val;
}
}; 第二种:基于数组构造链表并模拟删除过程
在严蔚敏,吴伟民编著的《数据结构》一书中,提到了一种基于数组实现链表的方法。这种方法的好处是可一次性分配所有节点的内存,避免了在增删过程中频繁的 new/delete,进而提高程序的效率。当然缺点也很明显,当节点数量超过数组的容量时,需重新分配更大的数组并进行大量的复制。
该题预先知道节点数量的上限为 ,因此先构造一个长度为
的数组
next 用于存储链表。
pair<int, int> node[10000];
其中,first 为值域,second 为指针域。
class Solution {
public:
pair<int, int> node[10000];
int ysf(int n, int m) {
for (int i = 0; i < n; i++) {
node[i].first = i+1;
node[i].second = (i == n-1 ? 0 : i+1);
}
int pre = n-1;
while (n > 1) {
for (int i = 1; i < m; i++, pre = node[pre].second) {}
node[pre].second = node[node[pre].second].second;
n--;
}
return node[pre].first;
}
}; class Solution {
public:
int next[10000];
int ysf(int n, int m) {
for (int i = 0; i < n; i++) {
next[i] = (i == n-1 ? 0 : i+1);
}
int pre = n-1;
while (n > 1) {
for (int i = 1; i < m; i++, pre = next[pre]) {}
next[pre] = next[next[pre]];
n--;
}
return pre+1;
}
}; 4ms
class Solution {
public:
int f(int n, int m) {
if (n == 1) {
return 0;
}
return (m + f(n-1, m)) % n;
}
int ysf(int n, int m) {
return f(n,m)+1;
}
}; 