二维数组的查找

牛客网链接:二维数组中的查找_牛客题霸_牛客网 (nowcoder.com)


题目要求:

提供一个二维数组array,其每行顺序按照从左往右从小到大排序,每列顺序从上到下从大到小排序,现要求我们完成一个函数,输入一个整数target,并判断数组中是否有这个数。

此时先假设一个数组:

int main()
{
    int arr[5][5] = {{1,2,3,4,5},{11,12,13,14,15},{21,22,23,24,25}
    {31,32,33,34,35},{41,42,43,44,45}};
    int target = 0;
    scanf("%d",&target);
    if(Find(***,***...))
        printf("yes\n");
    return 0;
}

满足上述条件后,就可以开始着手写函数了(函数参数待定这里用**表示),完成这个Find函数,可以从几个解题思路入手:

1.暴力枚举

int Find(int arr[5][5], int n)
{
    //遍历数组
    for(int i = 0;i < 5 ; i++)
    {
        for(int j = 0 ; j < 5 ; j++ )
        {
            //arr[i][j]等于n直接返回true
            if(arr[i][j] == n)
                return 1;
        }
    }
    //遍历了一遍数组函数还没结束,说明数组中没有这个数
    return 0;
}

但是当数组超级大时,运算量会极大极大,会给电脑带来很大的负荷。因此需要一个能带来效率的算法来实现;

2.利用数组特性

我们仔细分析,不难发现,对于杨氏矩阵老说,右上角和左下角的元素是有特点的。右上角的元素是一行中最大的,一列中最小的。左下角的元素是一行中最小的,是一列中最大的。所以我们可以从右上角或者左下角开始查找。比如:从右上角开始查找的时候,右上角的元素比我们要查找元素小,我们就可以去掉右上角元素所在的这一行;右上角的元素比我们要查找的元素大,我们就可以去掉右上角元素所在的这一列。然后依然找右上角的元素继续和要查找的元素与比较。这样每一次比较去掉一行或者去掉一列。这个查找效率是高于遍历数组元素的,所以时间复杂度是小于O(N),也满足题目要求。

int Find(int arr[][5] ,int x ,int y ,int n)
{
    int i = 0, j = y - 1; //从右上角开始遍历
    while (j >= 0 && i < x)
    {
        if (a[i][j] < f) //比我大就向下
        {
            i++;
        }
        else if (a[i][j] > f) //比我小就向左
        {
            j--;
        }
        else
        {
            return 1;
        }
    }
    return 0;
}

此时函数实参传递x = 5, y = 5,具体情况还要看矩阵的尺寸大小。

可以看到程序直接拿每行的最后一个元素与target相比较,则可以节省去很大一部分时间。

3.二分查找:

二分查找的示例在之前已经讲过,与之不同的是,这次的二分查找应用在二维数组上,对此有不理解的可以翻阅我往期的文章,在这里不做过多介绍:;

往期我们知道二分查找有一个严苛的条件,那就是数组必须按照顺序排列,而在满足条件的情况下使用二分查找无疑可以大大提高运算效率;

思路:

首先找到中间数,如果中间数大于要找的target,就在其上和其右查找,当本行数组第一个元素大于target时,就让矩阵的下限拉到中间行的上一行,然后重复以上步骤;当本行数组第一个元素小于target时,就让矩阵的最右端拉到中间列的前一个坐标。同理,中间数小于要找的target,操作就反正来😊。

上代码:

int Find(arr[][5],int n)
{
    int up = 0, down = 5;
    int left = 0, right = 5;
    int flag = 1;
    int row_rid = up + (down - up) / 2;
    int col_rid = left + (right - left) / 2;
    while (left <= right && up <= down)
    {
        if ((arr[0][0] <= n) && (arr[ROW - 1][COL - 1] >= n))
        {
            //列里二分查找
            if (arr[row_rid][col_rid] > n)
            {
                if (arr[row_rid][0] > n)
                    down = row_rid - 1;
                //在行里二分查找
                else
                    right = col_rid;
            }
            else if (arr[row_rid][col_rid] < n)
            {
                if (arr[row_rid][ROW - 1] < n)
                    up = row_rid + 1;
                //在行里二分查找
                else
                    left = col_rid;
            }
            else
            {
                printf("yes\n");
                flag = 0;
                break;
            }
        }
        else
        {
            printf("no\n");
            flag = 0;
            break;
        }
        row_rid = up + (down - up) / 2;
        col_rid = left + (right - left) / 2;
    }
    if (flag)
        printf("no\n");
}

这就是大概的思路啦,还有其他新奇的思路欢迎下方留言,大家互相学习相互支持哦。😊😊😊😊

  • 3
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值