華爲2016研發工程師[編程題]刪數

一、題目描述

在這裏插入圖片描述

二、解題思路

這道題有點像約瑟夫環,但是又不是,因爲在一輪刪除(指刪除數據的範圍剛好大於N)中,刪除的數的位置是確定的,而不依賴於該輪中先刪除的數的位置。這一點相比於約瑟夫環問題有所不同
但是此題又可以使用約瑟夫環問題的思想來求解,我們可以構建環形鏈表存放數據

  • 如果傳入的N<=1N <= 1,我們應該不進行處理,直接退出
  • 如果傳入的N==3N==2N == 3 || N == 2,那麼我們可以馬上知道該刪除的是哪個數字
  • 開始構建含有NN個元素的環形無頭結點的鏈表
  • 設第一次進行刪除操作時,要刪除的那個元素是某個元素後面的第三個元素,設這個元素是first,那麼進行第一輪刪除時,我們應該可以發現這個first實際上就是環形鏈表的尾節點
  • 進行完一輪操作後,我們應該仍舊把現在的鏈表當做第一次進行操作的那個環形鏈表,這個問題的關鍵是,將first節點移動到什麼位置
    • 我們發現,在刪除了一個頭結點後,下一個first如果想達到同樣的效果,則必須移動到first->next->next的位置,如此才能保證循環下去
    • 但是,如果當前環形鏈表只剩下三個元素,根據語句auto del = first->next->next->next;可以看出,del指向的就是first本身,如果它被釋放了,first就變成了一個野指針,後續語句first = first->next->next;也是無效的,這也是爲什麼在起初要判斷N==3N==2N == 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\%的測試用例

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章