《剑指offer》第六十二题:圆圈中最后剩下的数字

// 面试题62:圆圈中最后剩下的数字
// 题目:0, 1, …, n-1这n个数字排成一个圆圈,从数字0开始每次从这个圆圈里
// 删除第m个数字。求出这个圆圈里剩下的最后一个数字。

#include <cstdio>
#include <list>

using namespace std;

// ====================方法1====================
int LastRemaining_Solution1(unsigned int n, unsigned int m)
{
    if (n < 1 || m < 1)
        return -1;

    list<int> numbers;
    for (unsigned int i = 0; 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个数字. 从本位计算第一个数字, 因此是m-1
        {
            ++current;
            if (current == numbers.end()) //环式链表
                current = numbers.begin();
        }

        list<int>::iterator next = ++current; //删除后指向的数字 k+1
        if (next == numbers.end()) //环式链表
            next = numbers.begin();

        --current;
        numbers.erase(current); //删除第m个数字
        current = next;
    }
    return *current;
}

// ====================方法2====================
// 数学推导牛逼
int LastRemaining_Solution2(unsigned int n, unsigned int m)
{
    if (n < 1 || m < 1)
        return -1;

    int last = 0;
    for (int i = 2; i <= n; ++i)
        last = (last + m) % i;

    return last;
}
// ====================测试代码====================
void Test(const char* testName, unsigned int n, unsigned int m, int expected)
{
    if (testName != nullptr)
        printf("%s begins: \n", testName);

    if (LastRemaining_Solution1(n, m) == expected)
        printf("Solution1 passed.\n");
    else
        printf("Solution1 failed.\n");

    if (LastRemaining_Solution2(n, m) == expected)
        printf("Solution2 passed.\n");
    else
        printf("Solution2 failed.\n");

    printf("\n");
}

void Test1()
{
    Test("Test1", 5, 3, 3);
}

void Test2()
{
    Test("Test2", 5, 2, 2);
}

void Test3()
{
    Test("Test3", 6, 7, 4);
}

void Test4()
{
    Test("Test4", 6, 6, 3);
}

void Test5()
{
    Test("Test5", 0, 0, -1);
}

void Test6()
{
    Test("Test6", 4000, 997, 1027);
}

int main(int argc, char* argv[])
{
    Test1();
    Test2();
    Test3();
    Test4();
    Test5();
    Test6();

    return 0;
}
测试代码

分析:推导过程很好。效率提升近8倍。

class Solution {
public:
    int LastRemaining_Solution(int n, int m)
    {
        if (n < 1 || m < 1)
            return -1;
        
        list<int> numbers;
        for (unsigned int i = 0; i < n; ++i)
            numbers.push_back(i);
        
        list<int>::iterator current = numbers.begin();
        while (numbers.size() > 1)
        {
            for (int i = 1; i < m; ++i)
            {
                ++current;
                if (current == numbers.end())
                    current = numbers.begin();
            }
            
            list<int>::iterator next = ++current;
            if (next == numbers.end())
                next = numbers.begin();
            
            --current;
            numbers.erase(current);
            current = next;

        }
        return *current;
    }
};
牛客网-方法一
class Solution {
public:
    int LastRemaining_Solution(int n, int m)
    {
        if (n < 1 || m < 1)
            return -1;
        
        int last = 0;
        for (int i = 2; i <= n; ++i)
            last = (last + m) % i;
        
        return last;
    }
};
牛客网-方法二

 

posted @ 2020-04-12 22:12  源周率  阅读(123)  评论(0编辑  收藏  举报