数组算法-二分法三个Demo

    • 有序数组中查询目标值下标

在一个有序数组中查询目标值的下标,找到直接返回下标,找不到返回-1,此处用二分法就特别合适,主要原因是升序的数组,且还给了目标值,那么直接将数组分为两半,取中间值和目标值对比,小于就从前面循环到数组的一半,大于呢就从数组的一半循环到数组结束,也就是说这样就解除了O(n)时间复杂度,变为了O(logn),也就是说查找直接省去了一半的遍历。

那么下面就是代码了,还蛮简单的

public int searchTargetNum(int array[], int target) {
        int sizeHalf = array.length / 2;
        if (sizeHalf <= 0) {
            return -1;
        }
        // 得到分割的值
        int middleVal = array[sizeHalf];
        if (middleVal == target) return sizeHalf;

        // 判断从头找到值的分割,还是从分割处找到结尾
        int index = 0;
        int size = 0;
        if (middleVal > target) {
            size = sizeHalf;
        } else {
            index = sizeHalf;
            size = array.length;
        }

        for (int i=index;i<size;i++){
            if (array[i]==target){
                return i;
            }
        }
        return -1;
    }

测试一下

public static void main(String[] args) {
        int[] nums=new int[5];
        nums[0]=6;
        nums[1]=7;
        nums[2]=8;
        nums[3]=12;
        nums[4]=16;
        ArrayDemo arrayDemo=new ArrayDemo();
        System.out.println(arrayDemo.searchTargetNum(nums,7));
        System.out.println(arrayDemo.searchTargetNum(nums,8));
        System.out.println(arrayDemo.searchTargetNum(nums,13));
    }

结果:返回对应值在数组中的下标

2. 找出数组中出现次数超过一半的数字

这个使用二分法的原因是,需要超过数组的一半,用数组/2就代表一半,而将每一次出现的数字存储起来,当再次遇到直接累加,最后判断当前数字是否大于等于数组/2的值,大于等于则代表已经超过一半了,思路代码如下:

   // 二分法-找出数组中出现次数超过一半的数字
    public int MoreThanHalfNum_Solution(int[] array) {
        int numSize = array.length;
        if (numSize == 0) {
            return 0;
        }
        // 向上取整,为了后续判断数字出现的次数是否超过一半
        int halfSize = (int) Math.ceil((double) numSize / 2);
        // 将出现过的数字存储hash里
        Map<Integer, Integer> map = new HashMap<>();
        for (int num : array) {
            int count = 0;
            // 已经出现过的数字则需进行累加
            if (map.containsKey(num)) {
                count = map.get(num) + 1;
                map.put(num, count);
            } else {
                // 第一次出现直接赋值为1
                map.put(num, 1);
                count = 1;
            }
            // 判断count是否已经超过了一半
            if (count >= halfSize) {
                return num;
            }
        }
        return 0;
    }

3. 旋转数组找最小值

如给定一组数组为[1,2,3,4,5]旋转为[3,4,5,2,1],然后找到旋转后数组里最小的值,如此例中最小值为1,如数组[1,5,6,8,9]旋转后[6,8,9,5,1],最小值为1

我的思路是连旋转连找到最小值,那么此处又运用了二分法,你可能会说旋转一个数组怎么也得是全部遍历怎么就使用二分法了呢,为什么使用,观察一下,旋转的分割点都在中间元素,把中间元素拿出来放入头部,后面的值依次这样,直到数组走完,再把前半部分的处理掉拼接到后面。

 // 旋转数组找最小值
    public int xzArrayFindMin(int array[]) {
        int sizeHalf = array.length / 2;
        int[] nums = new int[array.length];
        int index = 0;
        for (int i = sizeHalf; i < array.length; i++) {
            nums[index++] = array[i];
        }

        for (int i = sizeHalf - 1; i >= 0; i--) {
            nums[index++] = array[i];
        }
        return nums[index - 1];
    }

测试代码


    public static void main(String[] args) {
        int[] nums = new int[5];
        nums[0] = 6;
        nums[1] = 7;
        nums[2] = 8;
        nums[3] = 12;
        nums[4] = 16;
        ArrayDemo arrayDemo = new ArrayDemo();
        System.out.println(arrayDemo.xzArrayFindMin(nums));
    }

结果:

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值