杨氏矩阵( 时间复杂度要求小于O(N) )

简介: 有一个数字矩阵,矩阵的每行从左到右是递增的,矩阵从上到下是递增的,请编写程序在这样的矩阵中查找某个数字是否存在,且程序的时间复杂度要小于O(N);

问题描述:

       有一个数字矩阵,矩阵的每行从左到右是递增的,矩阵从上到下是递增的,请编写程序在这样的矩阵中查找某个数字是否存在,且程序的时间复杂度要小于O(N);

问题分析:

    经过初步分析后我们可以发现,这道题可以通过遍历数组的办法解决。

问题解决:

方法一:

由于代码过于简单我们直接上代码就行:

int find(int (*p)[4], int row, int col, int put)
{
        bool flag = false;
        for (int i = 0; i < row; i++)
        {
                for (int j = 0; j < col; j++)
                {
                       if (*(*(p + i) + j) == put)
                        {
                        printf("找到了,它位于矩阵的第%d行,第%d列\n", i + 1, j + 1);
                        flag = true;
                        break;
                        }
                }
        }
        if (flag == false)
        {
        printf("该数不在矩阵中,请重新输入\n");
        }
}
int main()
{
        int i = 0;
        int arr[3][4] = { {1,2,3,4} ,{5,6,7,8},{9,10,11,12} };
        printf("请输入要查找的数字:");
        while ((scanf_s("%d", &i)) != EOF)
        {
        find(arr, 3, 4, i);
        }
return 0;
}

方法二:


       方法一虽然可以得到正确结果,但是问题也很明显,就是我们每次查找都需要重新遍历一次数组,如果数组元素较少还可以接收,但是如果数组元素过多就会降低查找效率不能满足时间复杂度小于O(N)的题目要求,所以我们想到了方法二。  


       我们仔细分析,不难发现,对于杨氏矩阵来说,右上角和左下角的元素是有特点的:右上角的元素是一行中最大的,一列中最小的。左下角的元素是一行中最小的,是一列中最大的。所以我们可以从右上角或者左下角开始查找。


       比如:从右上角开始查找的时候,右上角的元素比我们要查找元素小,我们就可以去掉右上角元素所在的这一行;右上角的元素比我们要查找的元素大,我们就可以去掉右上角元素所在的这一列。然后依然找右上角的元素继续和要查找的元素与比较。这样每一次比较去掉一行或者去掉一列。这个查找效率是高于遍历数组元素的,所以时间复杂度是小于O(N),也满足题目要求。


步骤一:在主函数中创建一个二维数组

int arr[][3] = {{1,3,5},{3,5,7},{6,7,9}}

步骤二:创建查找函数find

void find(int (*a)[3], int row ,int col ,int findnum)
{
      int i = 0;
      int j  = row - 1; 
      while(j >=0 && i < row) //col>=0 确保数组列数不为0,i<row方便下面的排查不会越界
              {
                      if(*(a+i)[j] < findnum)   //如果查找位置小于findnum
                        {
                                i++;                  //行数加一,向下一行查找
                        }
                        else if(*(a+i)[j] > findnum)   //如果查找位置大于findnum
                        {
                                 j--;                      //列数减一,向上一列查找
                        }
                        else 
                        {
                               return 1;
                        }
              }
}

通过画图,我们不难发现右上角元素在二维数组中元素下标总是数组行数减一:

步骤三:完善主函数

int main()
{
    int a[][3] = { {1, 3, 5},
                  {3, 5, 7},
                  {5, 7, 9} };
    if (find(a, 3, 3, 2))              //只有当找到时返回值等于1是真,显示找到,否则显示未找到
    {
        printf("It has been found!\n");
    }
    else
    {
        printf("It hasn't been found!\n");
    }
    return 0;
}

整体代码如下:

int find(int (*a)[3], int row, int col, int findnum)   
{
    int i = 0, j = col - 1; 
    while (j >= 0 && i < row)
    {
        if ((*a+i)[j] < findnum) 
        {
            i++;
        }
        else if (*(a+i)[j] > findnum)
        {
            j--;
        }
        else
        {
            return 1;
        }
    }
    return 0;
}
int main()
{
    int a[][3] = { {1, 3, 5},
                  {3, 5, 7},
                  {5, 7, 9} };
    if (find(a, 3, 3, 2))
    {
        printf("It has been found!\n");
    }
    else
    {
        printf("It hasn't been found!\n");
    }
    return 0;
}


相关文章
|
6天前
|
算法 测试技术 C#
【单调队列】LeetCode1499:满足不等式的最大值
【单调队列】LeetCode1499:满足不等式的最大值
【单调队列】LeetCode1499:满足不等式的最大值
|
6天前
|
算法 测试技术 C#
【折半处理 二分查找】1755. 最接近目标值的子序列和
【折半处理 二分查找】1755. 最接近目标值的子序列和
【折半处理 二分查找】1755. 最接近目标值的子序列和
|
5月前
|
算法 测试技术 C#
C++二分算法的应用:乘法表中第k小的数
C++二分算法的应用:乘法表中第k小的数
|
9月前
力扣 713. 乘积小于 K 的子数组
力扣 713. 乘积小于 K 的子数组
39 0
|
12月前
|
C++
【LeetCode 327】区间和的个数
【LeetCode 327】区间和的个数
leetcode剑指offer11—旋转数组的最小值(二分/边界值)
leetcode剑指offer11—旋转数组的最小值(二分/边界值)
|
存储 人工智能
归并排序例题——逆序对的数量
做道简单一点的题巩固一下
|
算法 C++
快排例题——第k个数
做道简单一点的题巩固一下
(归并排序)AcWing 788. 逆序对的数量
(归并排序)AcWing 788. 逆序对的数量
59 0
每日一题——乘积小于 K 的子数组
每日一题——乘积小于 K 的子数组
51 0
每日一题——乘积小于 K 的子数组