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

文章介绍了在给定递增的二维矩阵中高效查找特定数字的方法,通过从右上角或左下角出发,利用矩阵的递增特性逐步缩小查找范围,最终实现时间复杂度小于O(N)的查找算法。
摘要由CSDN通过智能技术生成

问题描述:

        有一个数字矩阵,矩阵的每行从左到右是递增的,矩阵从上到下是递增的,请编写程序在这样的矩阵中查找某个数字是否存在,且程序的时间复杂度要小于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;
}

~over~

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值