編程之美 - 尋找灌水王及擴展問題

問題描述:
在一個論壇中,一個ID發的帖子超過了半數,問怎樣能快速的找出這個ID。

算法描述:

書中給出了幾種不同的思考方式,
1) 先排序,然後逐個統計
2) 排序後,第 N/2個元素一定是這個ID

最好的方式是第三種,每次刪除兩個不同的ID,那麼水王的ID在剩下的列表中仍然超過一半。

或者可以這樣理解 假設總共有10個帖子,6個是水王的,假設水王的ID是 1
A :  [1,1,1,1,1,1]
B: [2,3,4,5]
從A中取一個,從B中取一個 刪除兩個,經過4輪刪除後後 剩下的就是水王的ID了。

算法的實現:用一個變量記錄當前操作的ID,一個變量記錄這個ID出現的次數。
如果當前操作的ID和 id_list[i]相同的話,就把ID出現的次數 +1;
如果不同ID出現的次數 -1,相當於一次刪除了兩個ID;
入當前ID出現的次數爲 0 了,說明當前操作的ID可能不是水王的,需要把ID換成id_list[i]在繼續操作


示例程序

#include <iostream>

using namespace std;

int find(int* arr, int len)
{
    int i = 0;
    int nCnt = 0;
    int nIndex = 0;

    for (i = 0; i < len; i++)
    {
        if (nCnt == 0)
        {
            nIndex = arr[i];
            nCnt++;
        }
        else
        {
            if (nIndex == arr[i])
                nCnt++;
            else
                nCnt--;
        }
    }
    return nIndex;
}

int main()
{
    int test[] = {8, 1, 1, 2, 3, 4, 5, 6,
                  8, 8, 8, 8, 8, 8, 8, 8,};
    int nLen = sizeof(test)/sizeof(test[0]);
    int nResult = -1;

    nResult = find(test, nLen);
    cout << "Find result = " << nResult << endl;
    cin >> nResult;

    return 0;
}

=================================================================

擴展問題:
在論壇中有三個ID,每個ID的發帖數都超過了1/4,快速找出這三個ID。

思考方法:
方向和一個ID是類似的,只不過將一個操作ID轉換爲一個操作ID列表。
或者叫水王備選ID列表,當id_list[i],與這個列表中某一個一致時,則把一致的 +1
否則,將列表中的都 -1,如果出現 0,則將該ID淘汰出水王備選列表。

示例程序:

#include <iostream>

using namespace std;

void debug_print(int index[], int count[])
{
    for (int i = 0; i < 3; i++)
    {
        cout << index[i] << ":"<< count[i] << endl;
    }
    cout << "=====================================" << endl;
}

int check(int index[], int count[], int target)
{
    int i = 0;
    for (i = 0; i < 3; i++)
    {
        if ((index[i] == target) || (count[i] == 0))
            return i;
    }
    return -1;
}

void find(int* arr, int len)
{
    int i = 0, j = 0;
    int curr = 0;
    int nCnt[3] = {0,0,0};
    int nIndex[3] = {0,0,0};

    for (i = 0; i < len; i++)
    {
        if ((curr = check(nIndex, nCnt, arr[i])) != -1)
        {
            if ((nIndex[curr] == 0) || nCnt[curr] == 0) nIndex[curr]= arr[i];
            nCnt[curr]++;
         }
        else
        {
            for (j = 0; j < 3; j++)
            {
                nCnt[j]--;
            }
        }
        debug_print(nIndex, nCnt);
    }

    if ((nCnt[0] > 0) || (nCnt[1] > 0) || (nCnt[2] > 0))
    {
        cout << nIndex[0] << "  "<< nIndex[1] << "  "<< nIndex[2] << "  " << endl;
    }
    else
    {
        cout << "None is larger than 1/4" << endl;
    }
}

int main()
{
    //int test[] = {1};
    //int test[] = {2, 1, 1, 2, 3, 4, 3, 3, 1, 2};  // N = 10  3:3:3:1
    //int test[] = {2, 1, 3, 4,};                   // N = 4  1:2:3:4 a fail case
    //int test[] = {1, 1, 1, 2, 4, 4, 3, 3, 1, 2,
    //              2, 1, 1, 2, 3, 4, 3, 3, 1, 2,
    //              2, 1, 1, 2, 3, 4, 3, 3, 1, 2};  // N = 30  10:8:8:4
    int test[] = {1, 1, 1, 2, 3, 2, 1, 3, 1, 2};    // N = 10  5:3:2
    int nLen = sizeof(test)/sizeof(test[0]);
    find(test, nLen);
    cin >> nLen;
    return 0;
}


發佈了235 篇原創文章 · 獲贊 31 · 訪問量 59萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章