杨氏矩阵( 时间复杂度要求小于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月前
|
算法 Java
LeetCode初级算法题:子数组最大平均数+二叉树的最小深度+最长连续递增序列+柠檬水找零
LeetCode初级算法题:子数组最大平均数+二叉树的最小深度+最长连续递增序列+柠檬水找零
55 0
|
8月前
|
Java
贪心 -力扣860.柠檬水找零力扣2208.将数组和减半的最少操作次数力扣179.最大数力扣376.摆动序列
贪心 -力扣860.柠檬水找零力扣2208.将数组和减半的最少操作次数力扣179.最大数力扣376.摆动序列
|
9月前
|
算法 测试技术 C#
【折半处理 二分查找】1755. 最接近目标值的子序列和
【折半处理 二分查找】1755. 最接近目标值的子序列和
|
Java 测试技术
hdu1231 最大连续子序列【动态规划】
hdu1231 最大连续子序列【动态规划】
46 0
LeetCode: 16. 最接近的三数之和 | 双指针专题
【LeetCode: 16. 最接近的三数之和 | 双指针专题 】
68 1
力扣 713. 乘积小于 K 的子数组
力扣 713. 乘积小于 K 的子数组
70 0
|
人工智能 测试技术
poj 3061 快慢指针寻找最短区间
翻译过来简而言之就是 第1行 输入测试的案例个数 第 i 行 输入N和S (N代表数组长度,S代表目标和) 寻找最短区间满足区间之和大于或者等于S 第 i+1行 输入数组元素
|
算法 C++
快排例题——第k个数
做道简单一点的题巩固一下
每日一题——乘积小于 K 的子数组
每日一题——乘积小于 K 的子数组
91 0
每日一题——乘积小于 K 的子数组
leetcode-每日一题1403. 非递增顺序的最小子序列(贪心)
时间复杂度:O(n logn) 其中n时数组长度,对数组进行排序需要O(n logn)的时间,对数组进行遍历需要O(n)的时间
109 0
leetcode-每日一题1403. 非递增顺序的最小子序列(贪心)