劍指offer-統計排序數組中某數字出現的次數

/*******************************************************************
Copyright(c) 2016, Tyrone Li
All rights reserved.
*******************************************************************/
// 作者:TyroneLi
//
 
/*
Q:
    數字在排序數組中出現的次數:
        統計一個數字在排序數組中出現的次數,例如輸入排序數組{1,2,3,3,3,4,5},由於
        3在排序數組中出現3次,因此輸出4.
S:
    1. 使用二分查找算法查找出該數字,那麼該數組分別向兩邊遍歷知道遇到不同數字爲止,
       那麼改數字出現的次數就可以通過兩次遍歷的次數加和得到。
    2. 借鑑二分查找算法,這裏只用找出第一個出現查找數字的位置以及最後一個查找位置,就
       可以求出該數字出現的次數;查找第一個出現的數字時候,如果二分查找的中間數字比需要
       查找的數字大,那麼需要查找的數字在前半部分,如果中間部分的數字比需要查找的數字小,
       那麼需要在後半部分查找;如果剛好等於,對於查找第一次出現的數字,如果該數字前面的
       數字不等於該數字,就爲所求,否則就是在前半部分繼續查找;對於最後一次出現的數字,
       如果後面的數字不等於該數字,則爲所求,否則繼續在後部分查找。
*/

#include <iostream>
#include <cstdio>
#include <cstdlib>

int binarySearch(int*data, int start, int end, int k)
{
    if(data == nullptr || start > end || start < 0)
        return -1;
    int mid = (start + end) / 2;
    if(data[mid] == k)
        return mid;
    else if(data[mid] < k)
        return binarySearch(data, mid+1, end, k);
    else
        return binarySearch(data, start, mid-1, k);
}

void test_binarySearch()
{
    int data[] = {1,2,3,4,5,6,7,8,9,10};
    int rst_idx = binarySearch(data, 0, 9, 3);
    for(auto e:data)
        std::cout << e << " ";
    std::cout << std::endl;

    std::cout << "idx = " << rst_idx << " data = " << data[rst_idx] << std::endl;
}

void test_binarySearch_2()
{
    int data[] = {1};
    int rst_idx = binarySearch(data, 0, 0, 1);
    for(auto e:data)
        std::cout << e << " ";
    std::cout << std::endl;

    std::cout << "idx = " << rst_idx << " data = " << data[rst_idx] << std::endl;
}

int countKNums_merge(int*data, int length, int k)
{
    if(data == nullptr || length <= 0)
        return -1;
    
    int k_idx = binarySearch(data, 0, length-1, k);
    if(k_idx < 0)
        return 0;
    int pre_k = 0;
    int post_k = 0;
    for(int i = k_idx; i >= 0; --i)
    {
        if(data[i] != k)
        {
            pre_k = i+1;
            break;
        }
    }

    for(int i = k_idx; i <= length; ++i)
    {
        if(data[i] != k)
        {
            post_k = i-1;
            break;
        }
    }
    // std::cout << "k_idx=" << k_idx << std::endl;
    // std::cout << "pre_k=" << pre_k << " post_k=" << post_k << std::endl;
    return (post_k - pre_k + 1);
}

int getFirstK(int*data, int length, int k, int start, int end)
{
    if(data == nullptr || length <= 0 || start > end)
        return -1;
    
    int mid = (start + end) / 2;
    int mid_data = data[mid];
    if(mid_data < k)
    {
        start = mid + 1;
    }else if(mid_data > k)
    {
        end = mid - 1;
    }else{
        if(mid == 0 || mid > 0 && data[mid-1] != k)
            return mid;
        else
            end = mid - 1;
    }
    return getFirstK(data, length, k, start, end);
}

int getLastK(int*data, int length, int k, int start, int end)
{
    if(data == nullptr || length <= 0 || start > end)
        return -1;
    
    int mid = (start + end) / 2;
    int mid_data = data[mid];
    if(mid_data < k)
    {
        start = mid + 1;
    }else if(mid_data > k)
    {
        end = mid - 1;
    }else{
        if(mid == (length - 1) || mid < (length - 1) && data[mid+1] != k)
            return mid;
        else
            start = mid + 1;
    }
    return getLastK(data, length, k, start, end);
}

int countKNums_FirstLast(int*data, int length, int k)
{
    if(data == nullptr || length <= 0)
        return -1;
    
    int number = 0;

    if(data != nullptr && length > 0)
    {
        int first_idx = getFirstK(data, length, k, 0, length-1);
        int last_idx = getLastK(data, length, k, 0, length-1);

        // std::cout << "first_idx=" << first_idx << " last_idx=" << last_idx << std::endl;
        
        if(first_idx >= 0 && last_idx >= 0)
        {
            number = last_idx - first_idx;
        }
    }
    return number;
}

void test_1()
{
    std::cout << "Test 1" << std::endl;
    int data[] = {1,2,3,3,3,3,4,5,6,7};
    for(auto e:data)
        std::cout << e << " ";
    std::cout << std::endl;
    int repeat_nums_1 = countKNums_merge(data, 10, 3);
    int repeat_nums_2 = countKNums_FirstLast(data, 10, 3);
    std::cout << " 3 repeat times : " << repeat_nums_1 << std::endl;
    std::cout << " 3 repeat times : " << repeat_nums_2 << std::endl << std::endl;
}

void test_2()
{
    std::cout << "Test 2" << std::endl;
    int data[] = {1,2,3,3,3,3,4,5,6,7};
    for(auto e:data)
        std::cout << e << " ";
    std::cout << std::endl;
    int repeat_nums_1 = countKNums_merge(data, 10, 8);
    int repeat_nums_2 = countKNums_FirstLast(data, 10, 8);
    std::cout << " 8 repeat times : " << repeat_nums_1 << std::endl;
    std::cout << " 8 repeat times : " << repeat_nums_2 << std::endl;
}

void test_3()
{
    std::cout << "Test 3" << std::endl;
    int data[] = {1,2,3,4,5,6,7,8,9,10};
    for(auto e:data)
        std::cout << e << " ";
    std::cout << std::endl;
    int repeat_nums_1 = countKNums_merge(data, 10, 3);
    int repeat_nums_2 = countKNums_FirstLast(data, 10, 3);
    std::cout << " 3 repeat times : " << repeat_nums_1 << std::endl;
    std::cout << " 3 repeat times : " << repeat_nums_2 << std::endl;
}

void test_4()
{
    std::cout << "Test 4" << std::endl;
    int data[] = {1,2,3,3,3,3,4,5,6,7};
    for(auto e:data)
        std::cout << e << " ";
    std::cout << std::endl;
    int repeat_nums_1 = countKNums_merge(data, 10, 1);
    int repeat_nums_2 = countKNums_FirstLast(data, 10, 1);
    std::cout << " 1 repeat times : " << repeat_nums_1 << std::endl;
    std::cout << " 1 repeat times : " << repeat_nums_2 << std::endl;
}

void test_5()
{
    std::cout << "Test 5" << std::endl;
    int data[] = {1,2,3,3,3,3,4,5,6,7};
    for(auto e:data)
        std::cout << e << " ";
    std::cout << std::endl;
    int repeat_nums_1 = countKNums_merge(data, 10, 7);
    int repeat_nums_2 = countKNums_FirstLast(data, 10, 7);
    std::cout << " 7 repeat times : " << repeat_nums_1 << std::endl;
    std::cout << " 7 repeat times : " << repeat_nums_2 << std::endl;
}

void test_6()
{
    std::cout << "Test 6" << std::endl;
    int data[] = {1,1,3,3,3,3,4,5,6,7};
    for(auto e:data)
        std::cout << e << " ";
    std::cout << std::endl;
    int repeat_nums_1 = countKNums_merge(data, 10, 1);
    int repeat_nums_2 = countKNums_FirstLast(data, 10, 1);
    std::cout << " 1 repeat times : " << repeat_nums_1 << std::endl;
    std::cout << " 1 repeat times : " << repeat_nums_2 << std::endl;
}

void test_7()
{
    std::cout << "Test 7" << std::endl;
    int data[] = {1,2,3,3,3,3,4,5,7,7};
    for(auto e:data)
        std::cout << e << " ";
    std::cout << std::endl;
    int repeat_nums_1 = countKNums_merge(data, 10, 7);
    int repeat_nums_2 = countKNums_FirstLast(data, 10, 7);
    std::cout << " 7 repeat times : " << repeat_nums_1 << std::endl;
    std::cout << " 7 repeat times : " << repeat_nums_2 << std::endl;
}

void test_8()
{
    std::cout << "Test 8" << std::endl;
    int data[] = {1};
    for(auto e:data)
        std::cout << e << " ";
    std::cout << std::endl;
    int repeat_nums_1 = countKNums_merge(data, 10, 1);
    int repeat_nums_2 = countKNums_FirstLast(data, 10, 1);
    std::cout << " 1 repeat times : " << repeat_nums_1 << std::endl;
    std::cout << " 1 repeat times : " << repeat_nums_2 << std::endl;
}

void test_9()
{
    std::cout << "Test 9" << std::endl;
    int*data = nullptr;
    // for(auto e:data)
    //     std::cout << e << " ";
    std::cout << std::endl;
    int repeat_nums_1 = countKNums_merge(data, 10, 3);
    int repeat_nums_2 = countKNums_FirstLast(data, 10, 3);
    std::cout << " 3 repeat times : " << repeat_nums_1 << std::endl;
    std::cout << " 3 repeat times : " << repeat_nums_2 << std::endl;
}

void test_countKNums()
{
    test_1();
    test_2();
    test_3();
    test_4();
    test_5();
    test_6();
    test_7();
    test_8();
    test_9();

}

int main(int argc, char**argv)
{

    // test_binarySearch();
    // test_binarySearch_2();
    test_countKNums();

    // std::system("pause");
    return 0;
}
 
 
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章