zoukankan      html  css  js  c++  java
  • 算法题001 剑指Offer 面试题三:二维数组中的查找

    剑指Offer题目1:二维数组中的查找

    题目描述: 

      http://ac.jobdu.com/problem.php?cid=1039&pid=0

      在一个二维数组中,每一行都按照从左到右递增的顺序排序,每一列都按照从上到下递增的顺序排序。

      请完成一个函数,输入这样的一个二维数组和一个整数,判断数组中是否含有该整数。

    输入:

      输入可能包含多个测试样例,对于每个测试案例,

      输入的第一行为两个整数m和n(1<=m,n<=1000):代表将要输入的矩阵的行数和列数。

      输入的第二行包括一个整数t(1<=t<=1000000):代表要查找的数字。

      接下来的m行,每行有n个数,代表题目所给出的m行n列的矩阵(矩阵如题目描述所示,每一行都按照从左到右递增的顺序排序,每一列都按照从上到下递增的顺序排序。

    输出:

      对应每个测试案例,

      输出”Yes”代表在二维数组中找到了数字t。

      输出”No”代表在二维数组中没有找到数字t。

     

    样例输入: 

    3 3

    5

    1 2 3

    4 5 6

    7 8 9

    3 3

    1

    2 3 4

    5 6 7

    8 9 10

    3 3

    12

    2 3 4

    5 6 7

    8 9 10

    样例输出:

    Yes

    No

    No

     

    题目解答分析

    失败解答1:用二维遍历

      这个题要是按普通的二维遍历来查找的话,也能完成功能,但是就体现不出二维数组原先有序的优势了。

      如果数组非常大的话,会特别浪费时间。

      但是我做的时候还是首先采取了这个二维遍历的方法,因为我开始想的是,我需要读入所有的数据,也只能一个一个读,这已经是一个二维遍历,那就只好在读的时候顺便进行查找了。

      程序如下:

    程序尝试1:双层循环
    #include <iostream>
    using namespace std;
    
    int main(int argc, char* argv[])
    {
        int row = 0, col = 0, t = 0;
        int testNum[100][100];
        bool isFound = false;
        while(cin >> row >> col >> t)
        {
            isFound = false;
            for(int i = 0; i < row ; ++i)
            {
                for(int j = 0; j < col; ++j)
                {
                    //输入每个数
                    cin>>testNum[i][j];
    
                    //边输入边验证
                    if(false == isFound && t == testNum[i][j])
                    {    
                        //已经找到后就没必要再找了
                        isFound = true;
                    }
                }
            }
            if(true == isFound)
            {
                cout << "Yes" << endl;
            }
            else
            {
                cout << "No" << endl;
            }
        }
    
        return 0;
    }

      果然提交以后就显示Time Limit Exceed了。

      想必,未显示的测试用例中必然有很大的二维数组。

    进一步思考:利用数组有序特点

      所以题目给的有序的条件是必须要用的,但是注意到这个有序也不是单纯的有序,行与行之间也只是上面的元素比下面的元素小的关系,并不代表第二行的数一定大于第一行,比如第一行可以是1,2,3,4,而第二行可以是2,3,4,5。

      先定位行再定位列的想法也不行,因为不论是第一列还是最后一列,都不足以作为本行的键值,因为各行之间的元素还是可能重叠的。而且,比如,目标值t有可能比第一列的所有元素都大,所以想根据第一个元素来查找是不行的。

    书中的思路:

      从数组中选取数字,和目标数字的关系有三种情况:=,<或>。

      如果是等于则查找成功;

      如果是数组中元素小于要查找的数字,说明要查找的数字应该在当前位置的右边下边。

      如果是数组中元素大于要查找的数字,说明要查找的数字应该在当前位置的左边上边。

      但是这两个区域还有可能有重叠,比如右边或下边会在右下角有重叠。

      解决方法:

      如果查找从右上角开始,如果要查找的数字不在右上角,则每次可以剔除一列或一行。

      也可以从左下角开始,但是不能从左上角或者右下角开始。 

    别人的解答

      http://www.cnblogs.com/remlostime/archive/2012/11/21/2780352.html

      于是搜到了如上的解答。

      可见这个查找是从矩阵的右上角开始进行的(本行最大,本列最小);

      如果查找成功,则返回;

      如果查找失败,矩阵元素值比t小则下移一行,矩阵元素值比t大则左移一列。

      这样把大小关系和调整的两个方向就分开了,经过一些移动,如果查找成功则返回Yes,如果矩阵走完,则表明没有找到。

      这样是可以实现(实现代码附在后面),可以通过本文所列的测试用例,但是提交到九度上,还是超时了。

      暂时没有解决办法,先休息吧,很晚了。。

     

    题目解答代码 

    解答方法2
    #include <iostream>
    using namespace std;
    
    
    
    int main(int argc, char* argv[])
    {
        int row = 0, col = 0, t = 0;
        int testNum[1000][1000];
        bool isFound = false;
        while(cin >> row >> col >> t)
        {
            
    
            //先将数组全部读入
            for(int i = 0; i < row ; ++i)
            {
                for(int j = 0; j < col; ++j)
                {
                    //输入每个数
                    cin>>testNum[i][j];
                }
            }
    
            //标志变量,记录查找是否成功
            isFound = false;
    
            //然后进行查找
            for(int i = 0, j = col -1; false == isFound && i < row && j >= 0;)
            {
                //找到之后循环就不必再进行
                if(testNum[i][j] == t)
                {
                    isFound = true;
                }
                else if(testNum[i][j] < t)
                {
                    ++i;
                    //换到下一行
                }
                else
                {
                    --j;
                    //换到前一列
                }
    
            }
    
            //最后输出结果
            if(true == isFound)
            {
                cout << "Yes" << endl;
            }
            else
            {
                cout << "No" << endl;
            }
        }
    
        return 0;
    }

    工具推荐

      一个测试程序很方便的工具,使用如图:

     

      首先设置好测试用例和标准输出(即正确情况下的输出),然后加入要运行的程序的exe文件(注意每次修改代码都需要重新加一次),最后点击运行即可查看结果。如果正确,会有对话框显示AC。

      附上网盘分享链接:

      http://pan.baidu.com/share/link?shareid=518071&uk=2701745266

       在测试用例比较长的时候不用每次都重复输入耽误时间了。

     

    参考资料:

      《剑指Offer:名企面试官精讲典型编程题》九度Online Judge收录:

      http://ac.jobdu.com/contest.php?cid=1039

      何海涛的日志:

      http://zhedahht.blog.163.com/blog/#m=0

      解法:

      http://www.cnblogs.com/remlostime/archive/2012/11/21/2780352.html

     

  • 相关阅读:
    Ext简单demo示例
    git命令行操作
    js继承方式
    一次活动总结
    h5自定义audio(问题及解决)
    JavaScript标准参考教材(alpha)--笔记
    css揭秘--笔记(未完)
    css权威指南--笔记
    h5上传图片及预览
    gulp入门小记
  • 原文地址:https://www.cnblogs.com/mengdd/p/2951085.html
Copyright © 2011-2022 走看看