[算法] 牛客题 精选算法入门——数组

1.NC29 二维数组中的查找

题目:

二维数组中的查找_牛客题霸_牛客网

考点:数组相关、特性观察、时间复杂度把握

 思路:假如我们给一个上图所示的数组,我们可以从右上角或者右下角的数开始比较,这里我们选择右上角。

        比如我们经过比较,发现这个 4 要大于我们比较的那个值,那我们就可以把 4 那一列排除掉(排除原因根据题目描述,这个数组的特征)。

        这个时候我们还是选择右上角的那个数,发现这个 3 要小于我们比较的那个值 ,那么我们就可以把 3 这一行 排除掉

        这样的算法可以使我们一次排除一行或者一列,比起我们双层循环比较每次只能排除一个数(效率低),很显然这个算法要更好一点。

查找的过程,本质是排除的过程

public class Solution {
    public boolean Find(int target, int [][] array) {
        if(array == null){
            return false;
        }
        int i = 0;
        int j = array[0].length - 1;
        while(i < array.length && j >= 0){
            if(target < array[i][j]){
                // 排除这一列
                j--;
            } else if (target > array[i][j]){
                // 排除这一行
                i++;
            } else {
                // 找到了
                return true;
            }
        }
        // 没找到
        return false;
    }
}

2.NC71 旋转数组的最小数字

题目:旋转数组的最小数字_牛客题霸_牛客网

考点:数组理解、二分查找、临界条件

常规思路:遍历这个数组然后一个一个比较看把小的那一个记录下来,最后遍历完成就得到了最小的那一个。

查找的过程,本质是排除的过程

这种查找一次只能遍历一个,一次也只能排除一个,性能较低。

本题思路:二分查找,定义首位下标,因为是非递减数组旋转,所以旋转后可以看成两部分,前半部分整体非递减,后半部分整体非递减,前半部分整体大于后半部分。

我们定义 left 是最左侧,right 是最右侧,mid 二分之后的中间位置

 

if(mid >= left)说明mid 属于我们划分后的前半部分,我们实际要找的值在mid 的右侧,left = mid

if(mid < left)说明mid 属于我们划分后的后半部分,我们实际要找的值在mid 的左侧,right = mid

public class Solution {
    public int minNumberInRotateArray(int [] array) {
        if(array == null || array.length == 0){
            return 0;
        }

        int left = 0;
        int right = array.length - 1;
        int mid = 0;

        while (array[left] >= array[right]){
            if(right - left == 1){
                // 说明 left 和 right 已经相邻了
                mid = right;
                break;
            }

            // 如果两个初始值都超过int 限定的大小,left + right 会发生溢出
            // 所以不能写成:(left + right) >> 1
            mid = left + ((right - left) >> 1);

            // 里面的值可以重复,当遇到left、right、mid值都相等时,我们就没办法判断了
            // 这里我们就进行线性操作,遍历去寻找
            if(array[left] == array[right] && array[mid] == array[left]) {
                int result = array[left];
                for (int i = left + 1; i < result; i++) {
                    if(array[i] < result) {
                        result = array[i];
                    }
                }
                return result;
            }
            if(array[mid] >= array[left]){
                // 说明mid 处于前半部分的非递减中,我们要找的就是后半部分的第一个值
                left = mid;
            } else {
                right = mid;
            }
        }
        return array[mid];
    }
}

3.NC77 调整数组顺序使奇数位于偶数前面(一)

题目:调整数组顺序使奇数位于偶数前面(一)_牛客题霸_牛客网

考点:数组操作、排序思想的扩展使用

思路:从前往后,把偶数往后移,腾出位置,放入奇数

public class Solution {
    public int[] reOrderArray (int[] array) {
        if(array == null || array.length == 0){
            return new int[0];
        }

        int k = 0;
        for(int i = 0;i < array.length;i++){
            if(array[i] % 2 == 1){
                // 是奇数
                // 把该奇数之前的所有偶数向后移动
                int temp = array[i];
                int j = i;
                while (j > k){
                    array[j] = array[j - 1];
                    j--;
                }
                array[k] = temp;
                k++;
            }
        }
        return array;
    }
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值