华为2016研发工程师[编程题]删数

一、题目描述

在这里插入图片描述

二、解题思路

这道题有点像约瑟夫环,但是又不是,因为在一轮删除(指删除数据的范围刚好大于N)中,删除的数的位置是确定的,而不依赖于该轮中先删除的数的位置。这一点相比于约瑟夫环问题有所不同
但是此题又可以使用约瑟夫环问题的思想来求解,我们可以构建环形链表存放数据

  • 如果传入的 N < = 1 N <= 1 ,我们应该不进行处理,直接退出
  • 如果传入的 N = = 3 N = = 2 N == 3 || N == 2 ,那么我们可以马上知道该删除的是哪个数字
  • 开始构建含有 N N 个元素的环形无头结点的链表
  • 设第一次进行删除操作时,要删除的那个元素是某个元素后面的第三个元素,设这个元素是first,那么进行第一轮删除时,我们应该可以发现这个first实际上就是环形链表的尾节点
  • 进行完一轮操作后,我们应该仍旧把现在的链表当做第一次进行操作的那个环形链表,这个问题的关键是,将first节点移动到什么位置
    • 我们发现,在删除了一个头结点后,下一个first如果想达到同样的效果,则必须移动到first->next->next的位置,如此才能保证循环下去
    • 但是,如果当前环形链表只剩下三个元素,根据语句auto del = first->next->next->next;可以看出,del指向的就是first本身,如果它被释放了,first就变成了一个野指针,后续语句first = first->next->next;也是无效的,这也是为什么在起初要判断 N = = 3 N = = 2 N == 3 || N == 2 的原因。那么只剩下了三个数据,马上就可以根据当前first的位置判断出要返回的是哪个节点的数据。

三、解题代码

#include <iostream>
using namespace std;
class LNode {
public:
    int data;
    LNode *next;

    explicit LNode(int a) {
        data = a;
        next = nullptr;
    }
};

void sln(unsigned int N) {
    if (N <= 1) return;
    if (N == 2) {
        cout << 0 << endl;
        return;
    }
    if (N == 3) {
        cout << 2 << endl;
        return;
    }
    if (N > 1000) N = 1000;
    auto head = new LNode(-10);
    auto p = head;
    for (unsigned int i = 0; i < N; i++) {
        auto ins = new LNode(i);
        p->next = ins;
        p = ins;
    }
    p->next = head->next;
    delete head;
    head = nullptr;
    auto first = p;
    unsigned int remain = N;
    while (1) {
        auto del = first->next->next->next;
        first->next->next->next = del->next;
        delete del;
        del = nullptr;
        first = first->next->next;
        remain--;
        if (remain == 3) {
            cout << first->next->next->data << endl;
            return;
        }
    }
}

int main() {
    unsigned int N;
    while (cin >> N) {
        sln(N);
    }
    return 0;
}

第二次做

#include <iostream>
#include <list>
using namespace std;
int main()
{
    int n;
    while (cin >> n)
    {
        n = min(1000, n);
        list<int> l;
        for (int i = 0; i < n; i++)
            l.insert(l.end(), i);
        auto iter = l.begin();
        while (l.size() > 1)
        {
            for (unsigned short counter = 0; counter < 2; counter++)
                if (++iter == l.end())
                    iter = l.begin();
            auto del = iter;
            if (++iter == l.end())
                iter = l.begin();
            l.erase(del);
        }
        cout << *iter << endl;
    }
    return 0;
}

四、运行结果

通过了 100 % 100\% 的测试用例

猜你喜欢

转载自blog.csdn.net/weixin_44587168/article/details/105517504