• 有序二维数组查找的两种方法:从左上角(递归)和右上角(非递归)出发


    有序二维数组查找

    这道题是在学习剑指offer这本书看到的,原题如下所示:
      在一个二维数组中,每行都按照从左到右递增的顺序排序,每列都按照从上到下递增的顺序排序。请完成一个函数,输入这样的一个二维数组和一个整数,判断数组中是否含有该整数。

    分块治之

    在拿到题目的时候,我并没有找到右上角那么优秀的特征,所以我选择二分查找的有序数组的思想,最初的想法是从最小值(左上角)到最大值(右下角)进行扇形搜索。
    在这里插入图片描述
    例如上边的这个数组,但是发现该数组并不具备这样的条件,因为扇形搜索的话,同半径下的元素,例如9,9,7,6这四个元素并不相等,但是发现一个有趣的规律,假如我沿着该矩阵左上角最大最小值这样的对角线,针对7这个元素进行搜索,搜索到绿色区域10这个元素时,绿色部分均大于等于10,进而大于7,而黄色部分均小于7,这样便可以将黄,绿两个区域进行排除,只搜索蓝色区域即可,同时针对蓝色区域同样执行一样的搜索模式,这样的话便可以分块递归处理了。同时为了处理不对称情况作出了以下处理:

    1. 只针对矩阵中从左上角出发最大的正形矩阵进行搜索,剩下的矩阵(粉红区域)下一步搜索
    2. 对于当前搜索矩阵,当在对角线搜索到目标值时,返回当前搜索区域已搜索到目标值
    3. 当前搜索矩阵左上角第一个元素大于目标值时,返回当前搜索区域无目标值
    4. 当前搜索矩阵右下角第一个元素小于目标值时,返回当前搜索区域无目标值
    5. 当前搜索矩阵对角线中部存在大于目标值元素时,搜索进一步该元素的蓝色区域

    学过数据结构与算法的同学一样就可以看出这个算法的弊端,当这个二维数组退化为一维数组时,本算法的时间复杂度也会退化成(O(n))。不过作为脑海中的第一种实现方法,我还是打算把它记录下来。代码如下 :

    template <typename item>
    bool _FindInPartiallySortedMatrixTopLeft(item *array, item value, int startx, int starty, int endx, int endy,
                                             int column) {
        assert(startx <= endx && starty <= endy);
        int currentrow = endx - startx;
        int currentcolumn = endy - starty;
        int count = currentrow < currentcolumn ? currentrow : currentcolumn;
    //            std::cout << startx << "," 
    //                     << starty << "-->"
    //                     << endx << ","
    //                     << endy << "
    ";
        item currentItem = 0;
        int currentX = startx;
        int currentY = starty;
        for (int i = 0; i <= count; ++i, ++currentX, ++currentY) {
            currentItem = array[currentX * column + currentY];
            if (currentItem == value) {
                return true;
            } else if (currentItem > value) {
                if (i == 0) return false;
                else {
                    if (_FindInPartiallySortedMatrixTopLeft(array, value, currentX, starty, endx, currentY - 1,
                                                            column))  return true;
                    return _FindInPartiallySortedMatrixTopLeft(array, value, startx, currentY, currentX - 1, endy,
                                                               column);
                }
            }
        }
        currentX --;
        currentY --;
        if (currentrow > currentcolumn) {
            if (currentX == endx) return false;
            else
                return _FindInPartiallySortedMatrixTopLeft(array, value, currentX + 1, starty, endx, endy, column);
        } else {
            if (currentY == endy) return false;
            else
                return _FindInPartiallySortedMatrixTopLeft(array, value, startx, currentY + 1, endx, endy, column);
        }
    }
    
    template <typename item>
    bool FindInPartiallySortedMatrixTopLeft(item *array, item value, int row, int column){
        return _FindInPartiallySortedMatrixTopLeft(array, value, 0, 0, row - 1, column - 1, column);
    }
    

    剑指offer解法

    当然从右上角搜索是更为优化的一种算法了,因为这个算法是利用单列最小这个特性所以跟矩阵形状无关,如下图所示,直接从右上角对该矩阵进行搜索,当右上角元素大于目标元素时,直接排除其所在这一列(绿色区域),当右上角元素小于目标元素,直接排除这一行(蓝色区域),这样的话每一步搜索都可以对一行(列)进行排除,搜索效率较高。
    在这里插入图片描述

    template <typename item>
    bool FindInPartiallySortedMatrixTopRight(item *matrix, item number, int rows, int columns)
    {
        bool found = false;
    
        if(matrix != nullptr && rows > 0 && columns > 0)
        {
            int row = 0;
            int column = columns - 1;
            while(row < rows && column >=0)
            {
    //                    std::cout << row << "," 
    //                     << column << "-->"
    //                     << rows-1 << ","
    //                     << 0 << "
    ";
                if(matrix[row * columns + column] == number)
                {
                    found = true;
                    break;
                }
                else if(matrix[row * columns + column] > number)
                    -- column;
                else
                    ++ row;
            }
        }
    
        return found;
    }
    

    编写的自动化测试代码如下:

    template <typename T>
    void test_find_sorted_matrix(const std::string &findName, bool (*find)(T *, T, int, int), T *array, int value,
                                 int rows, int columns, bool expect, int count = 10000000) {
        clock_t startTime, endTime;
        startTime = clock();
        for (int i = 0; i < count; ++i) {
            assert(find(array, value, rows, columns)==expect);
        }
        endTime = clock();
        std::cout<<findName << " : "<<(double)(endTime-startTime)/CLOCKS_PER_SEC<<" s."<<std::endl;
    }
    
    void test_all_find_sorted_matrix(int n,int m,int count = 1){
    	assert(n < 21 && m < 21);
    	int array[n][m];
    	for (int k = 0; k < m; ++k) {
    	   array[0][k] = k;
    	}
    	for (int i = 1; i < n; ++i) {
    	   for (int j = 0; j < m; ++j) {
    	       array[i][j] = array[i-1][j] + array[i-1][m-1];
    	   }
    	}
    	
    	for (int i = 0; i < n; ++i) {
    	   for (int j = 0; j < m; ++j) {
    	       std::cout << array[i][j] << "	";
    	   }
    	   std::cout << "
    ";
    	}
    	int value = array[rand()%n][rand()%m];
    	test_find_sorted_matrix("Find Top Right Corner", flame::CodingInterviewChinese::FindInPartiallySortedMatrixTopRight<int>, (int *) array,
    	                       value, n, m,true, count);
    	test_find_sorted_matrix("Find Top Left Corner", flame::CodingInterviewChinese::FindInPartiallySortedMatrixTopLeft<int>, (int *) array,
    	                       value, n, m, true,count);
    	}
    }
    

    性能测试

    经测试从左上角搜索,只针对对角线元素性能较优(2-3倍),从右上角搜索整体较优(2-3倍),感兴趣的朋友可以运行测试一下。

    任世事无常,勿忘初心
  • 相关阅读:
    SQL Server调优系列基础篇(常用运算符总结——三种物理连接方式剖析)
    SQL Server调优系列基础篇
    《SQL Server企业级平台管理实践》读书笔记——SQL Server中关于系统库Tempdb总结
    你所不知道的SQL Server数据库启动过程(用户数据库加载过程的疑难杂症)
    你所不知道的SQL Server数据库启动过程,以及启动不起来的各种问题的分析及解决技巧
    《SQL Server企业级平台管理实践》读书笔记——几个系统库的备份与恢复
    Struts2
    Struts2
    Struts2
    Struts2
  • 原文地址:https://www.cnblogs.com/FlameBlog/p/14715238.html
Copyright © 2020-2023  润新知