21 Востаннє редагувалося steamwater (11.08.2024 09:19:36)

Re: Рекурсивний пошук по двовимірній впорядкованій матриці

koala написав:
steamwater написав:

Це не стiлькi про матрицю, скiльки про target. Можуть бути такi значення, що їх нема не тiльки у двох наперед заданих квадрантах, а й в 3-х чи 4-х...

І що? Пошук ведеться в 3-х квадрантах, але 2 з них об'єднані в один прямокутник. Якщо не знайдеться - значить, останній виклик поверне false, ото й усе.

Це я й мав на увазi. Коли нема зовсiм, то аж 4 виклики. А це залежить саме вiд значення, що шукається. Тобто не знайти - дорожче, чим знайти. Це справедливо, для будь якого алгоритму пошуку.
Що до прямокутника, то допоки ви його не обiйдете (кожен з 2-х квадрантiв), то нема впевненостi, чи є там щось, чи нi i логiка ледащого обчислювання умовних вирвзiв це вiдображає: if(a || b) -> b не обчислюватимется якщо a поверне true. Але ж вирогiднiсть цього 1/4, а для a=false - 3/4. Вирогiднiсть, того що b поверне false разом з a вже значно нижча:(2/3)*(3/4)=1/2. Тож  виходить, що я не помилявся i в цьому, з початку?
Проте ж головна проблема, здаєцця, не в тому. Ви дивилися мiй тест?

22

Re: Рекурсивний пошук по двовимірній впорядкованій матриці

Ну як там буде 4 виклики? Викликів не більше 2, навіть якщо не знайдеться. Власне, не знайдеться чи знайдеться на останньому кроці - складність однакова.

Подякували: leofun011

23 Востаннє редагувалося steamwater (12.08.2024 10:27:41)

Re: Рекурсивний пошук по двовимірній впорядкованій матриці

koala написав:

Ну як там буде 4 виклики? Викликів не більше 2, навіть якщо не знайдеться.

Я це описав.

if(a || b) {}
else
if(c || d) {}

Умови обчислюються ледащо.

int invoke_counter(0);

bool condition(int found) {
    ++invoke_counter;
    if(found) return true;
    return false;
}
int main() {
    int not_found = 0; // не знайдено
    int found = 1; // знайдено
    
    // знайдено 0
    std::cout << "no invokage was saccesful\n";
    if(condition(not_found) || condition(not_found));
    else
        if(condition(not_found) || condition(not_found));
    std::cout << "found never " << invoke_counter; // 4

    invoke_counter=0;
    // знайдено на 4 виклику
    std::cout << "\n\n4-th invokage was saccesful\n";
    if(condition(not_found) || condition(not_found));
    else
        if(condition(not_found) || condition(found));
    std::cout << "\nfound in " << invoke_counter; // 4

    invoke_counter=0;
    // знайдено на 3 виклику
    std::cout << "\n\n3-th invokage was saccesful\n";
    if(condition(not_found) || condition(not_found));
    else
        if(condition(found) || condition(found));
    std::cout << "\nfound in " << invoke_counter; // 3

    invoke_counter=0;
    // знайдено на 2 виклику
    std::cout << "\n\n2-th invokage was saccesful\n";
    if(condition(not_found) || condition(found));
    else
        if(condition(found) || condition(found));
    std::cout << "\nfound in " << invoke_counter; // 2

    invoke_counter=0;
    // знайдено на 1 виклику
    std::cout << "\n\n1-th invokage was saccesful\n";
    if(condition(found) || condition(found));
    else
        if(condition(found) || condition(found));
    std::cout << "\nfound in " << invoke_counter; // 1

    return 0;
}
koala написав:

Власне, не знайдеться чи знайдеться на останньому кроці - складність однакова.

Звичайно.
Ви дивились тест? Там можна змiнювати налаштування, але ваш варiант показує дуже низьку эффективнiсть. Я помилок не знайшов, проте хвилююсь. Може ви знайшли?

24

Re: Рекурсивний пошук по двовимірній впорядкованій матриці

steamwater написав:
if(a || b) {}
else
if(c || d) {}

Умови обчислюються ледащо.

Нехай, але у мене немає такого коду. Очі розуйте. У мене

if(умова1) {
    return a || b;
} else {
    return c || d;
}
Подякували: wander, leofun012

25 Востаннє редагувалося steamwater (12.08.2024 11:25:22)

Re: Рекурсивний пошук по двовимірній впорядкованій матриці

koala написав:
steamwater написав:
if(a || b) {}
else
if(c || d) {}

Умови обчислюються ледащо.

Нехай, але у мене немає такого коду. Очі розуйте. У мене

if(умова1) {
    return a || b;
} else {
    return c || d;
}

Охх... Дiйсно, - вибачте. То ж виходить що, таки максiмум 2... Тодi чому, на вашу думку, тест свiдчить про таку низьку швидкiсть?

26 Востаннє редагувалося koala (12.08.2024 12:14:19)

Re: Рекурсивний пошук по двовимірній впорядкованій матриці

У вас матриця дуже щільно близькими значеннями заповнюється, в результаті у вас практично в першиму ж рядку пошук знаходить потрібне значення і складність падає до O(log(N)). Поставте

const int num_max = 10'000'000;

чи біля того, щоб трохи розрядити числа.

Подякували: steamwater1

27

Re: Рекурсивний пошук по двовимірній впорядкованій матриці

Але при цьому швидкість виходить досить близькою, тобто мій алгоритм усе одно O(Nlog(N)). Два виклики рекурсії вбивають логарифм.

28 Востаннє редагувалося steamwater (13.08.2024 00:35:11)

Re: Рекурсивний пошук по двовимірній впорядкованій матриці

koala написав:

У вас матриця дуже щільно близькими значеннями заповнюється, в результаті у вас практично в першиму ж рядку пошук знаходить потрібне значення і складність падає до O(log(N)). Поставте

const int num_max = 10'000'000;

чи біля того, щоб трохи розрядити числа.

Це, - слушне зауваження. Дiйсно, якщо пощукове значення мiстится десь на початку матрицi, то змагання не рiвне. Я вирiшив дiапазон пошуку почати з середини, а закiнчити на одну чверту пicля.

const int num_min = num_max / 2;
const int v_size = 1000; // 10
const int search_number = 1000000; // 5

отак iнiцiалiзуєцця вектор значеннь для пошуку:

std::vector<std::vector<int>>
    matrix (
        make_matrix(0, num_max, v_size) // початок з нуля
    );
    std::vector<int> vtargets = make_source_vector(
        num_min, num_max + num_min / 2, search_number
    );
    // оскiльки num_min = num_max / 2 то перша половина матрицi не бере участь у пошуцi
    // а змiщення верхнього рубежу гарантуе присутнicть чвертi невдалих спроб

кiлькicть повторiв вплива тiльки на точнiсть, але я iї збiльшив до мiльйону. Але це не дуже вплинуло. Треба ще щось придумати.
Навiть

const int num_min = 3 * num_max / 4; // num_max / 2

допомогає, але не дуже .
А от пiдвищення верхньої  межi дiапазону пошуку (збiльшення частки невдалих спроб), показує могутню стабiльнiсть вашого алгоритму, у той час як мiй сповiльнюється кратно до вказаної частки. Тож за певних умов, ваш має виграти)

29

Re: Рекурсивний пошук по двовимірній впорядкованій матриці

На leetcode автоматична оцінка показує, що складність мого алгоритму - O(M+N).

Ще ідея оптимізації: доки розміри не Mx1 чи 1xN, різати по коротшій стороні, а якщо це вузька смужка, то запускати звичайний бінарний пошук. Складність має трохи впасти, хоча й не асимптотично.
Також для тестування краще підходить не рандомна матриця, а щось на кшталт

[[1, 2, 3, 4],
 [5, 6, 7, 8],
 [9,10,11,12]]

Умова виконується, пошук 0 чи m*n+1 буде гарантовано невдалим, і дуже легко перевіряти пошук по кутах чи квадрантах.

30

Re: Рекурсивний пошук по двовимірній впорядкованій матриці

Я спробував. Тобто уся 2d матриця заповнена рядом вiд 0 до dim*dim. Шукав даннi середнього рядку.

std::vector<std::vector<int>>
    matrix(v_size);
    size_t num(0);

    for(auto &subvec:matrix) {
        for(size_t i = 0; i < v_size; ++i) {
            subvec.push_back(num++);
        }
    }
    std::vector<int> vtargets = matrix[v_size / 2]; // посерединi
    std::cout << "\nfind_in_matrix\n";
    {
        simple_timer st;
        for(auto target : vtargets) {
            bool res = find_in_matrix(matrix, target);
            // cout << res << '\n';
        }
    }
    std::cout << "\nSolution\n";
    Solution sol;
    {
        simple_timer st;
        for(auto target : vtargets) {
            bool res = sol.searchMatrix(matrix, target);
            // cout << res << '\n';
        }
    }

Але швидкість майже у 10-теро менше нiж у мойого. Я думаю, що те що мойому доводится мати N/2 невдалих спроб, вiн легко це долає за рахунок швидкої перевiрки дiапазону, у той час як вашому треба зробити по 2 рекурсiї. Хех... Здається, це досить непросте завдання, знайти алгоритм заповнення такої матрицi данними, що зроблять ваш алгоритм швидкiшим.

31

Re: Рекурсивний пошук по двовимірній впорядкованій матриці

Чекайте, а ви які налаштування оптимізації використовуєте?

Подякували: steamwater1

32

Re: Рекурсивний пошук по двовимірній впорядкованій матриці

koala написав:

Чекайте, а ви які налаштування оптимізації використовуєте?

У-у-пс... Дiйсно. Я не перключився у релiз. Тепер, набагато краще! Але текучий тест трохи все ж таки трохи повiльнiший за мiй. А попереднiй - де початок набору цiлей з 3/4 num_max - у 5 разiв.

33

Re: Рекурсивний пошук по двовимірній впорядкованій матриці

Може, визначимося з тим, що ми тестуємо? І у мого коду, і у вашого в кращому разі складність O(1) - якщо перший же перевірений елемент буде шуканим.
Якщо шуканий елемент є в першому перевіреному рядку, то ваш алгоритм дає O(log(N)), а мій складніший, бо він шукатиме ще й інших місцях. Зате якщо він є на діагоналі і спершу у мене перевіряти маленький прямокутник, то вже мій алгоритм даватиме O(log(N)), а не ваш.
Зате оцінка по найгіршій ситуації у вас стабільно O(Nlog(N)). А от у мене - щось не виходить нормально оцінити.
По-перше, мій алгоритм в будь-якому разі перевірятиме кожен рядок. Тобто множник N там буде. Але лише log(N) рядків будуть перевірені по всій довжині; 2log(N) рядків буде перевірено на половину довжини (тобто потребуватимуть log(N/2) кроків), 4log(N) - на чверть і т.д. Але чи то я вже всю математику забув, чи то воно нормально не обчислюється... Може, leofun01 допоможе?

Подякували: steamwater, leofun012

34 Востаннє редагувалося steamwater (15.08.2024 22:01:56)

Re: Рекурсивний пошук по двовимірній впорядкованій матриці

koala написав:

Може, визначимося з тим, що ми тестуємо?

Саме це я й маю на увазi, коли говорю про те, що знайти алгоритм пошуку послiдовностi, що маматиме шукатися у у матрицi, росподiлення у якiй теж нетривiальне (сопряжено до першої, сформульованої задачи), це досить непросто, принаймнi, для мене. Але без цього, неможливо визачити межi застосовністi вашого алгоритму. Поки що схоже на те, що у разi ровномiрного розподiлення у пошуковому iнтервалi, та матрицi стосовно заданого iнтервалу значень, ваш алгоритм програє. Доречи, сам алгоритм заповнення матрицi, згiдно обмежень задачи цього топику - досить теж задача не проста у загальнiй постановцi. Я вже писав, що якщо даннi у матрицi сортованi, то то є часний випадок, але для нього я (спочатку не розiбравши докладно), написав бiнарний пошук у бiнарному пошуцi. Це значно швидше, нiж спочатку перебирати, а потiм бiнарити...
С iншого боку, обмеження задачi досить неприроднi i не мають загального сенсу. Тож мiркувати над цим, це суто академiчне питання. Може воно й не вартe часу. Ось чому я не люблю задачi сформульованi математиками якi не цiкавляться питаннями здорового глузду. Я вже про це кеазав. Але де шукати iньшi я теж не знаю. В цiлому хочу подякувати Teg Miles, за топик, що викликав нашi роздуми i вам та iншiм учасникам за участь.

35 Востаннє редагувалося steamwater (15.08.2024 18:39:52)

Re: Рекурсивний пошук по двовимірній впорядкованій матриці

Цей код, здаєцця має шукати навiть у не впорядоченiй матрицi по int елементах. Я не тестував прискипливо, але щось воно знаходить... Teg Miles, якщо маєте чаc i надхнення, - потестiть. Працює дуже швидко.

//bool
std::pair<int, int>
 find_in_matrix_quick(
                         const std::vector<std::vector<int>>& matrix,
                         const int target
                         )
{
    using Vec=std::vector<int>;
    Vec vtarget={target};
    auto vec_it=
         std::upper_bound(matrix.begin(), matrix.end(), vtarget,
                               [](const Vec &a, const Vec &b){
                                return a.back()<b.back();
                                }
                               );

        for(;vec_it!=matrix.end() && *vec_it->begin()<target; ++vec_it)
        {
            auto it=std::lower_bound(vec_it->begin(), vec_it->end(), target);
               if(*it==target)
                 {
                     //return true;
                     return {vec_it-matrix.begin(), vec_it->begin()-it};
                 }
        }
    //return false;
    return{-1,-1};
}

/////////////////тест часу:
std::pair<int,int> found_pair;//це щоб перевiрити чи воно щось находить... Можна б взагалi пiдрахувати кiлькiсть вдалих спроб, та часу зараз бракує. 

     std::cout<<"\nfind_in_matrix\n";
     {
         int once(0);
         simple_timer st;

         for(auto target:vtargets)
         {
           auto res=find_in_matrix_quick(matrix, target);
           if (!once && res.first!=-1){
            found_pair=res;
            ++once;
           }
          // cout<<res<<'\n';
         }
     }
     std::cout<<"\nfirstly found is "<<matrix[found_pair.first][found_pair.second]<<"\n";

36

Re: Рекурсивний пошук по двовимірній впорядкованій матриці

koala написав:

2log(N) рядків буде перевірено на половину довжини (тобто потребуватимуть log(N/2) кроків), 4log(N) - на чверть і т.д. Але чи то я вже всю математику забув, чи то воно нормально не обчислюється... Може, leofun01 допоможе?

га ? я аж чайом подавився. В чому треба допомога ?

O( sum{ c*log(N/k) } ) так й залишиться O( log(N) ).
Тільки продукт добуток O( product{ c*log(N/k) } ) трохи більший ніж O( log(N) ).
А якщо треба { код | алґоритм }, то це почекає до вихідних коли появляться сили.

37

Re: Рекурсивний пошук по двовимірній впорядкованій матриці

Так там не просто sum{ c*log(N/k) }, а sum{ (2^k log(N/2^k)^2 }. Ніби. Якщо нічого не наплутав.

38

Re: Рекурсивний пошук по двовимірній впорядкованій матриці

koala написав:

sum{ (2^k log(N/2^k)^2 }

Тоді log(N/2^k) = log(N) - k*log(2), і оцінка буде .. а ні, не буде, десь дужка пропала, не знаю як це читати.

39

Re: Рекурсивний пошук по двовимірній впорядкованій матриці

steamwater написав:

Я не тестував прискипливо, але щось воно знаходить

А щось - ні.

40 Востаннє редагувалося steamwater (16.08.2024 16:09:57)

Re: Рекурсивний пошук по двовимірній впорядкованій матриці

Так. В тестi 1000х1000 середнiй рядок знайшла 998 разiв) Треба дивитись. Краще б воно не находило 998... Легше було б шукати помилку)
Попередня версiя знаходить 1000, як треба.
Зненацька, виявилось що ваша, чомусь знайшла лише 9...

const int num_max=100000
;
const int num_min=0
;
const int v_size=1000
;

std::vector<std::vector<int>>
     matrix (
     make_matrix(num_min, num_max, v_size)     );

     std::vector<int> vtargets=matrix[v_size/2];//посерединi
 
    int once(0);

     std::cout<<"\nfind_in_matrix\n";
     {
         simple_timer st;

         for(auto target:vtargets)
         {
           auto res=find_in_matrix(matrix, target);
          // auto res=find_in_matrix_quick1(matrix, target);
          // if (!once && res.first!=-1){
                 if (res)   {++once;}
         
         }
     }
     std::cout<<"\nfirstly found  "<<once<<"\n";//1000 ok

     once=0;

     std::cout<<"\nSolution\n";
     Solution sol;

     {
         simple_timer st;

         for(auto target:vtargets)
         {
                bool res=
         sol.searchMatrix(matrix, target);

          if (res)   { ++once; }
       
         }
     }

      std::cout<<"\nfirstly found  "<<once<<"\n";//9 not ok