[LeetCode每日1题][简单] 面试题62. 圆圈中最后剩下的数字

题目

面试题62. 圆圈中最后剩下的数字 - 力扣(LeetCode)
在这里插入图片描述

数学+递归解法

长度为n的序列中,我们要删除的第一个元素位置是m % n。删除完第一个元素后,得到的是一个长度为n - 1的子序列,假设这个子序列的下标从0开始,如果我们能知道这个子序列进行删除操作后,最后剩余的元素下标x,那么原序列最后剩余的元素下标应为(m % n + x) % n = (m + x) % n。即f(n, m) = (m + f(n - 1, m)) % n

class Solution
{
public:
    int f(int n, int m)
    {
        if (n == 1)
            return 0;
        int x = f(n - 1, m);
        return (x + m) % n;
    }
    int lastRemaining(int n, int m)
    {
        return f(n, m);
    }
};

尾递归还可以转成循环,节省栈空间:

class Solution
{
public:
    int lastRemaining(int n, int m)
    {
        int x = 0; // 序列长度为1时
        for (int i = 2; i <= n; i++) // 序列长度为2~n时
        {
            x = (x + m) % i;
        }
        return x;
    }
};

暴力解法

一开始用的是单向循环链表,不出意外超时了。

class Solution
{
    struct Node
    {
        int val;
        Node *next;
        Node(int v) : val(v), next(NULL) {}
    };

    void add(Node *node)
    {
        tail->next = node;
        tail = node;
        node->next = head;
    }

    void remove(Node *&cur, int count) 
    {
        Node *pre;
        for (int i = 1; i < count; i++)
        {
            pre = cur;
            cur = cur->next;
        }
        pre->next = cur->next;
        if (cur == head)
        {
            head = cur->next;
        }
        if (cur == tail)
        {
            tail = pre;
        }
        cur = cur->next; // 传入的是指针引用,可以作用到实参
    }

    Node *head = new Node(0);
    Node *tail = head;

public:
    int lastRemaining(int n, int m)
    {

        for (int i = 1; i < n; i++)
        {
            add((new Node(i)));
        }
        Node *cur = head;
        while (head != tail)
        {
            remove(cur, m);
        }
        return head->val;
    }
};

参考

圆圈中最后剩下的数字 - 圆圈中最后剩下的数字 - 力扣(LeetCode)

posted @ 2020-03-30 15:23  zaqny  阅读(131)  评论(0编辑  收藏  举报