ʚ自在飞花ɞ | 约瑟夫环的三种实现方式

题目链接

三种方式

  • 第一种:在堆上构造链表并模拟删除过程
    • 时间复杂度:
    • 空间复杂度:
  • 第二种:基于数组构造链表并模拟删除过程
    • 时间复杂度:
    • 空间复杂度:
  • 第三种:递推公式
    • 时间复杂度:
    • 空间复杂度:

第一种:在堆上构造链表并模拟删除过程

这种方法是最直观的了。首先,定义如下结构体,用于存储链表。

    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-1pre=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;
    }
};
全部评论

相关推荐

04-14 20:10
已编辑
门头沟学院 Java
点赞 评论 收藏
分享
评论
点赞
收藏
分享

创作者周榜

更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务