1

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

Умови:
Двовимірна матриця натуральних чисел, де кожен елемент рядка більше за наступний (зліва направо),
і кожен елемент стовпця більше за наступний (згори донизу).
Треба знайти задане число за допомогою рекурсії.

Це завдання з LeetCode.
Я намагався використати бінарний пошук, але він не спрацьовує
при деяких розмірах матриці (коли лише один рядок або лише один стовпчик).
Потрібна порада як дати раду з такими розмірами.
Ось код:

#include <iostream>
#include <vector>
using namespace std;

void helper(vector<vector<int>> &matrix, int &low, int &high,
    const int &row, const int &col, const int &target, bool &answer)
{
    if (low <= high) {
        int mid = (low + (high - low) / 2);
        cout << matrix[mid / row][mid % col] << endl;
        if (matrix[mid / row][mid % col] == target) {
            answer = true;
            return;
        }
        if (matrix[mid / row][mid % col] < target) {
            low = mid + 1;
            helper(matrix, low, high, row, col, target, answer);
        } else {
            high = mid - 1;
            helper(matrix, low, high, row, col, target, answer);
        }
    }
}
bool searchMatrix(vector<vector<int>> &matrix, int target) {
    if (matrix.size() == 0) {
        return false;
    }
    int row = matrix.size() - 1;
    int col = matrix.at(0).size() - 1;
    int low = 0;
    int high = row * col - 1;
    bool answer { false };
    helper(matrix, low, high, row, col, target, answer);
    return answer;
}
int main() {
    /*vector<vector<int>> matrix {
        { 1, 4, 7, 11, 15 },
        { 2, 5, 8, 12, 19 },
        { 3, 6, 9, 16, 22 },
        { 10, 13, 14, 17, 24 },
        { 18, 21, 23, 26, 30 }
    };*/
    vector<vector<int>> matrix { { 1, 2 } };
    int target { 2 };
    bool answer = searchMatrix(matrix, target);
    cout << answer << endl;
    return 0;
}
Подякували: steamwater1

2

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

Teg Miles написав:
matrix[mid / row][mid % col]

А ви можете пояснити, що саме ви тут намагаєтеся зробити? Від мене, випускника математичного ліцею та факультету прикладної математики КПІ, глибинний сенс цієї сакральної дії якось утікає. Ви ж ніби бінарний пошук по двох координатах ведете, чи ні?

3

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

Ну тобто це класичний спосіб загнати дві координати в одне число, а потім їх звідти витягнути; проблема в тому, що якщо
mid/row лінійно залежить від mid, то mid%col уже залежить нелінійно. (mid+1)/row>=mid/row для позитивних row; але (mid+1)%col може бути як більше, так і менше за mid%col, наприклад 7%4=3, але 8%4=0.
А у вас дві координати, і те, що значення в центрі більше за шукане, дозволяє відсіяти лише чверть матриці, а не половину, і тим більш не половину за вашими формулами.

         v < M      |     v ? M
                    |       
--------------------M--------------
                    |
         v ? M      |     v > M

Зліва зверху все менше за M; справа знизу все більше за M; але в двох чвертях по вторинній діагоналі взагалі невідомо що, треба запускати по два бінарні пошуки.

Подякували: Teg Miles1

4 Востаннє редагувалося steamwater (08.08.2024 13:49:39)

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

Teg Miles, я в котре бачу у вас бажання вигадати додатковi обмеження на постановку задачi. Наприклад, використання смарт пойнтерiв там де вони не потрiбнi, використання at() на векторi всюди де можливо i т.д.
У текучому топiку, ви вирiшили використати рекурсiю у явному виглядi... А де ви бачили у текстi задачi про рекурсiю?
Ось варiант з використанням std. Якщо засвербить - прошу, перепишить на ще бiльш страшному Ровнокодi. /Лiтера Р використана з метою уникнути реклами того що нi кому не потрiбно) /

#include <iostream>
#include <algorithm>

template<typename T>
std::pair<int, int> find_in_matrix(
                         const std::vector<std::vector<T>> &matrix,
                         const T &target
                         )
{    
    int row_ind(0);
    for(const auto &vec:matrix)
    {
       auto it=std::lower_bound(vec.begin(), vec.end(), target);
       if(*it==target)
         {
             return {   row_ind,
                        it-vec.begin()  };
         }

         ++row_ind;
    }

    return {-1,-1};
}

int main()
{
    std::vector<std::vector<int>> vec =        {
         {1,4,7,11,15}
        ,{2,5,8,12,19}
        ,{3,6,9,16,22}
        ,{10,13,14,17,24}
        ,{18,21,23,26,30}
                        };
    int target = 20;

   auto target_inds=find_in_matrix(vec, target);
   if(target_inds.first==-1)std::cout<<" fail\n";
   else std::cout<<"value of "<<target<<" has found at indexes "<<target_inds.first<<target_inds.second<<'\n';

//дуже не дебажив, але ось перевiрка на межах дiапазону
   target = 1;
   target_inds=find_in_matrix(vec, target);
   if(target_inds.first==-1)std::cout<<" fail\n";
   else std::cout<<"value of "<<target<<" has found at indexes "<<target_inds.first<<" and "<<target_inds.second<<'\n';

   target = 30;
   target_inds=find_in_matrix(vec, target);
   if(target_inds.first==-1)std::cout<<" fail\n";
   else std::cout<<"value of "<<target<<" has found at indexes "<<target_inds.first<<" and "<<target_inds.second<<'\n';

//а це у серединi
target = 5;
   target_inds=find_in_matrix(vec, target);
   if(target_inds.first==-1)std::cout<<" fail\n";
   else std::cout<<"value of "<<target<<" has found at indexes "<<target_inds.first<<" and "<<target_inds.second<<'\n';
    return 0;
}

5

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

steamwater написав:

Teg Miles, я в котре бачу у вас бажання вигадати додатковi обмеження на постановку задачi. Наприклад, використання смарт пойнтерiв там де вони не потрiбнi, використання at() на векторi всюди де можливо i т.д.
У текучому топiку, ви вирiшили використати рекурсiю у явному виглядi... А де ви бачили у текстi задачi про рекурсiю?
Ось варiант з використанням std. Якщо засвербить - прошу, перепишить на ще бiльш страшному Ровнокодi. /Лiтера Р використана з метою уникнути реклами того що нi кому не потрiбно) /

#include <iostream>
#include <algorithm>

template<typename T>
std::pair<int, int> find_in_matrix(
                         const std::vector<std::vector<T>> &matrix,
                         const T &target
                         )
{    
    int row_ind(0);
    for(const auto &vec:matrix)
    {
       auto it=std::lower_bound(vec.begin(), vec.end(), target);
       if(*it==target)
         {
             return {   row_ind,
                        it-vec.begin()  };
         }

         ++row_ind;
    }

    return {-1,-1};
}

int main()
{
    std::vector<std::vector<int>> vec =        {
         {1,4,7,11,15}
        ,{2,5,8,12,19}
        ,{3,6,9,16,22}
        ,{10,13,14,17,24}
        ,{18,21,23,26,30}
                        };
    int target = 20;

   auto target_inds=find_in_matrix(vec, target);
   if(target_inds.first==-1)std::cout<<" fail\n";
   else std::cout<<"value of "<<target<<" has found at indexes "<<target_inds.first<<target_inds.second<<'\n';

//дуже не дебажив, але ось перевiрка на межах дiапазону
   target = 1;
   target_inds=find_in_matrix(vec, target);
   if(target_inds.first==-1)std::cout<<" fail\n";
   else std::cout<<"value of "<<target<<" has found at indexes "<<target_inds.first<<" and "<<target_inds.second<<'\n';

   target = 30;
   target_inds=find_in_matrix(vec, target);
   if(target_inds.first==-1)std::cout<<" fail\n";
   else std::cout<<"value of "<<target<<" has found at indexes "<<target_inds.first<<" and "<<target_inds.second<<'\n';

//а це у серединi
target = 5;
   target_inds=find_in_matrix(vec, target);
   if(target_inds.first==-1)std::cout<<" fail\n";
   else std::cout<<"value of "<<target<<" has found at indexes "<<target_inds.first<<" and "<<target_inds.second<<'\n';
    return 0;
}

На LeetCode є навчальні картки, одна з них зветься Recursion II.
Саме там я побачив це завдання, тому намагаюся знайти рішення з рекурсією.

6 Востаннє редагувалося steamwater (08.08.2024 20:44:41)

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

Teg Miles написав:

На LeetCode є навчальні картки, одна з них зветься Recursion II.
Саме там я побачив це завдання, тому намагаюся знайти рішення з рекурсією.

У завданнi нiчого про рекурсiю нема. Але я ж написав, що ви можете написати рекурсивне рiшення. Для цього потрiбно написати свою lower_bound для одновимiрного впорядоченого контейнеру. Не дуже складно, але це не матиме аж нiякого стосунку до двомiрного масиву. Тож 99% тексту задачi некогерентна до левової частки складностi завдання. Тоб-то цей сайт, як на мене доволi тупий. Нема нiякого сенсу вчити рекурсiї таким чином. Краше мотивувати до використання std де це доцiльно.
Подивившись на свiй код трохи щiльнiше я б його дещо прискорив закривши код з lower_bound iз пошуком у такий блок:

if(vec.front()<=target && vec.back()>=target)
       {
           auto it=std::lower_bound(vec.begin(), vec.end(), target);
               if(*it==target)
                 {
                     return {   row_ind,
                                it-vec.begin()  };
                 }
       }
Подякували: Teg Miles1

7

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

steamwater написав:
Teg Miles написав:

На LeetCode є навчальні картки, одна з них зветься Recursion II.
Саме там я побачив це завдання, тому намагаюся знайти рішення з рекурсією.

У завданнi нiчого про рекурсiю нема. Але я ж написав, що ви можете написати рекурсивне рiшення. Для цього потрiбно написати свою lower_bound для одновимiрного впорядоченого контейнеру. Не дуже складно, але це не матиме аж нiякого стосунку до двомiрного масиву. Тож 99% тексту задачi некогерентна до левової частки складностi завдання. Тоб-то цей сайт, як на мене доволi тупий. Нема нiякого сенсу вчити рекурсiї таким чином. Краше мотивувати до використання std де це доцiльно.
Подивившись на свiй код трохи щiльнiше я б його трохи прискорив закривши код з lower_bound з пошуком у такий:блок

if(vec.front()<=target && vec.back()>=target)
       {
           auto it=std::lower_bound(vec.begin(), vec.end(), target);
               if(*it==target)
                 {
                     return {   row_ind,
                                it-vec.begin()  };
                 }
       }

А які є аналогічні кращі сайти? Hackerrank мені не подобається, там часто завдання доволі незрозуміло описані.

8 Востаннє редагувалося steamwater (12.08.2024 21:50:20)

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

Teg Miles написав:

               
А які є аналогічні кращі сайти? Hackerrank мені не подобається, там часто завдання доволі незрозуміло описані.

Вiдверто кажучи, не знаю. Якщо ваша мета тренування, то я б порадив аналiзувати завдання будь де i вичленяти з них суть, одкидаючи побiчне й недоцiльне. До речи, найбiльш эффективне рiшення до цього завдання, це сортувати двомiрний масив, а потiм пройти по нйому upper_bound для пошуку потрiбного подмасиву, а вже потiм по попередньйому до знайденого пiдмасива - lower_bound. Я так 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чний час не бачу як зробити. Якщо, хтось придумав як, - подивлюся.

9

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

Ось, будь ласка, повна рекурсія, максимальна ефективність:

class Solution {
public:
    using Matrix = std::vector<std::vector<int>>;
    bool searchMatrix(const Matrix &matrix, int target) {
        return searchMatrix(matrix, target, 0, matrix[0].size(), 0, matrix.size());
    }
    bool searchMatrix(const Matrix &matrix, int target, int x0, int x1, int y0, int y1) {
        if(x1==x0||y1==y0)
            return false;
        if(x1-x0==1 && y1-y0==1)
            return matrix[y0][x0]==target;
        int xmid = (x0+x1)/2;
        int ymid = (y0+y1)/2;
        if(matrix[ymid][xmid]==target)
            return true;
        else if(matrix[ymid][xmid]>target)
            return searchMatrix(matrix, target, x0, xmid, ymid, y1)
                || searchMatrix(matrix, target, x0, x1, y0, ymid);
        else 
            return searchMatrix(matrix, target, x0, xmid+1, ymid+1, y1)
                || searchMatrix(matrix, target, xmid+1, x1, y0, y1);
    }
};

Якщо хочете, можете легко переробити на цикл; знадобиться стек прямокутників для пошуку (спершу - вся матриця, потім - половинка і чверть, далі все менші).

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

10

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

Rust, рішення зі стеком
type Rect = [usize; 4];

fn push(stack: &mut Vec<Rect>, rect: Rect) {
    if rect[2]>rect[0] && rect[3]>rect[1] {
        stack.push(rect);
    }
}

impl Solution {
    pub fn search_matrix(matrix: Vec<Vec<i32>>, target: i32) -> bool {
        use std::cmp::Ordering::*;
        
        let mut stack = vec![[0,0,matrix[0].len(), matrix.len()]];
        while let Some([x0, y0, x1, y1]) = stack.pop() {
            let xmid = (x0+x1)/2;
            let ymid = (y0+y1)/2;
            match matrix[ymid][xmid].cmp(&target) {
                Greater => {
                    push(&mut stack, [x0, ymid, xmid, y1]);
                    push(&mut stack, [x0, y0, x1, ymid]);
                }
                Equal => return true,
                Less => {
                    push(&mut stack, [x0, ymid+1, xmid+1, y1]);
                    push(&mut stack, [xmid+1, y0, x1, y1]);
                    
                }
            }
        }
        false
    }
}
Подякували: leofun011

11 Востаннє редагувалося steamwater (09.08.2024 11:26:56)

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

koala написав:

Ось, будь ласка, повна рекурсія, максимальна ефективність:

Дякую, шановний koala. Чудове рiшення. Тоб-то у найгiршому випадку кожна ступiнь рекурсiї може викликати ще 4? Але навiть у такому випадку дiапазон буде зменшуватись у 2-чи на кожному кроцi, що повинно бути скорiше нiж 5 рекурсiй по всйому розмiрi сторони матрицi. Деякi накладнi за операцiї не мають бути суттєвими. Як буде трохи часу проведу тест на швидкiсть.

12

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

Як я вже пояснював вище, кожна перевірка відкидає 1/4 матриці. Решту 1/2 + 1/4 обробляють 2 рекурсивні виклики. Тобто діапазон зменшується у 4/3 рази, а це все та ж логарифмічна складність, просто база інша (не 2, а 4/3).

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

13 Востаннє редагувалося steamwater (09.08.2024 16:26:47)

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

Для мене, питання у тому, що таке перевiрка. Одна з гiлок нової рекурсiї у блоцi:

else if(matrix[ymid][xmid]>target)
            return searchMatrix(matrix, target, x0, xmid, ymid, y1)
                || searchMatrix(matrix, target, x0, x1, y0, ymid);
        else 
            return searchMatrix(matrix, target, x0, xmid+1, ymid+1, y1)
                || searchMatrix(matrix, target, xmid+1, x1, y0, y1);

Тут для того щоб дiйти до останнього треба пройти 3 попереднiх. Тож у найгiршому випадку, за 4 виклики ми скорочуемо об'ем  матрицi у 4 рази? Вiрно я зрозумiв?
Щодо скорочення у 2 рази - так, я помилився. Незвично менi ще думати двовимiрно.

14 Востаннє редагувалося koala (09.08.2024 21:12:08)

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

steamwater написав:

Вiрно я зрозумiв?

Ні. Розставляємо фігурні дужки:

else if(matrix[ymid][xmid] > target) {
    return searchMatrix(matrix, target, x0, xmid, ymid, y1)
        || searchMatrix(matrix, target, x0, x1, y0, ymid);
} else {
    return searchMatrix(matrix, target, x0, xmid+1, ymid+1, y1)
        || searchMatrix(matrix, target, xmid+1, x1, y0, y1);
}

Як бачите, буде виконано або одну гілку (2 виклики), або другу (теж два).
Ба більше, якщо перший виклик поверне true, то завдяки скороченому виконанню (short circute) оператора || другий виклик не відбудеться.

Подякували: leofun01, steamwater2

15

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

Тепер зрозумiв. Ви правi, - дякую.

16

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

Тут ще цікаві питання постають: чи ефективніше ділити на "довші" чи "квадратніші" прямокутники? А також спершу викликати менший пошук чи більший? Я так розумію, з погляду алгоритмічної складності це не має впливати; а от маржинально? Чи, може, непарні довжини вигідніші, бо додаткові значення відрізаються?

Подякували: leofun01, steamwater2

17 Востаннє редагувалося steamwater (10.08.2024 23:23:35)

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

koala, тут треба мiркувати. По формi менi ваш алгоритм до вподоби. Двовимiрне поле пошуку - двовимiрна рекурсiя.
Але я хочу повернутися до попереднього питання. Я вчора (та й сьогоднi) вже трохи втомлений. Тому даруйте менi певну недбалiсть у кодi що буде далi. Але спочатку мої аргументи. Я дарма згодився з вашими, останнього разу. Ви казали що виконуватиметься лише одна гiлка if. А це не так. I саме тому, що логiчнi вирази у першому if в данному випадку мають бути виконани всi. Бо логiчне або не припине перевiрку пiсля першого false. Тож у навiть половинi випадкiв буде 3 виклика, а у найгiршому, - 4.
Ще гiрше те, що основання логарифму значно блище до 1 анiж 2...
Менi дуже шкода. Правда. Єдина надiя, що я десь помилився:

#include <iostream>
#include <algorithm>
#include <random>
#include <chrono>

template<typename It>
void uniform_random_fill(int num_min, int num_max, It first, It last) {
    std::random_device r;
    std::mt19937 g(r());
    std::uniform_int_distribution<int> ud(num_min, num_max);
    while(first != last) *first++ = ud(g);
}
std::vector<int> make_source_vector(int num_min, int num_max, unsigned v_size) {
    std::vector<int> vec(v_size);
    uniform_random_fill(num_min, num_max, vec.begin(), vec.end());
    return vec;
}
std::vector<std::vector<int>> make_matrix(int num_min, int num_max, unsigned v_size) {    
    std::vector<std::vector<int>> matrix;
    auto vec = make_source_vector(num_min, num_max, v_size);
    for(int el : vec) {
        for(int &el : vec) el += 1;
        std::sort(vec.begin(), vec.end());
        matrix.push_back(vec);
    }
    return matrix;
}
void print_matrix(std::vector<std::vector<int>> const &v) {
    for(const auto &el : v) {
        for(const int in : el)
            std::cout << in << ' ';
        std::cout << '\n';
    }
    std::cout << '\n';
}
struct simple_timer {
    ~simple_timer() {
        std::chrono::duration<double> dur = std::chrono::steady_clock::now() - begin;
        std::cout << "\nThe time span was: " << dur.count() << "\n";
    }
    std::chrono::time_point<std::chrono::steady_clock> begin =
        std::chrono::steady_clock::now();
};
template<typename T>
// std::pair<int, int>
bool find_in_matrix(
    const std::vector<std::vector<T>> &matrix,
    const T &target
) {
    int row_ind(0);
    for(const auto &vec : matrix) {
        if(vec.front() <= target && vec.back() >= target) {
            auto it = std::lower_bound(vec.begin(), vec.end(), target);
                if(*it == target) {
                    return true;
                    // { row_ind, it - vec.begin() };
                }
        }
        ++row_ind;
    }
    return false;
    // { -1, -1 };
}
class Solution {
public:
    using Matrix = std::vector<std::vector<int>>;
    bool searchMatrix(const Matrix &matrix, int target) {
        return searchMatrix(matrix, target, 0, matrix[0].size(), 0, matrix.size());
    }
    bool searchMatrix(const Matrix &matrix, int target, int x0, int x1, int y0, int y1) {
        if(x1 == x0 || y1 == y0)
            return false;
        if(x1 - x0 == 1 && y1 - y0 == 1)
            return matrix[y0][x0] == target;
        int xmid = (x0 + x1) / 2;
        int ymid = (y0 + y1) / 2;
        if(matrix[ymid][xmid] == target)
            return true;
        else if(matrix[ymid][xmid] > target)
            return searchMatrix(matrix, target, x0, xmid, ymid, y1)
                || searchMatrix(matrix, target, x0, x1, y0, ymid);
        else
            return searchMatrix(matrix, target, x0, xmid + 1, ymid + 1, y1)
                || searchMatrix(matrix, target, xmid + 1, x1, y0, y1);
    }
};
const int num_min = 0;
const int num_max = 10;
const int v_size = 1000; // 10
const int search_number = 10000; // 5
int main() {
    std::vector<std::vector<int>>
    matrix(make_matrix(num_min, num_max, v_size));
    std::vector<int> vtargets=make_source_vector(num_min, 2*num_max, search_number);
    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';
        }
    }
    return 0;
}

Даруйте що не вiдформатував i може десь залишилося трохи робочого смiття. I за те що багатенько слiв, але ужати поки не вийшло.

18

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

Ви не могли б навести приклад значень matrix[ymid][xmid] та target, при яких буде виконано більше 2 рекурсивних викликів з однієї функції?

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

19 Востаннє редагувалося steamwater (10.08.2024 23:34:18)

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

koala написав:

Ви не могли б навести приклад значень matrix[ymid][xmid] та target, при яких буде виконано більше 2 рекурсивних викликів з однієї функції?

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

20

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

steamwater написав:

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

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