【面试算法】

山脉数组中查找目标值

给一个数组,元素大小先单调增再单调减,找一个目标数,如[1,4,9,32,50,100,21,7],找数字21,如果存在返回所在数组下标,不存在返回-1。

对应题目Leetcode:https://leetcode.cn/problems/find-in-mountain-array/description/

整体思路

  1. 根据二分找到最大节点
    1. 二分中间节点mid和mid+1比大小,可以确定mid右边处于增区间还是减区间
    2. 如果是增区间,最大值位置一定大于等于mid+1,二分的左指针移动到mid+1
    3. 如果是减区间,最大值位置一定小于等于mid,二分的右指针移动到mid
  2. 先在左侧二分找,找到直接返回
  3. 在右侧找然后返回

思考总结

类似在完全有序或分段区间内有序,理论上都可以借力二分解决。
如本题:山脉数组中查找目标值,另经典题:搜索旋转排序数组

代码实现

public int findInMountainArray(int target, MountainArray mountainArr) {
        int l = 0, r = mountainArr.length() - 1;
        // 找峰值点
        while (l < r) {
            int mid = (l + r) / 2;
            if (mountainArr.get(mid) < mountainArr.get(mid + 1)) {
                l = mid + 1;
            } else {
                r = mid;
            }
        }
        // 在左侧找target
        int res = bs(0, l, mountainArr, target, true);
        // 如果没找到,在右侧找target
        return res != -1 ? res : bs(l + 1, mountainArr.length() - 1, mountainArr, target, false);
    }
	// 二分查找
    public int bs(int l, int r, MountainArray mountainArr, int target, boolean flag) {
        while (l <= r) {
            int mid = (l + r) / 2;
            if (mountainArr.get(mid) == target) {
                return mid;
            }
            if (flag) {
                if (mountainArr.get(mid) > target) {
                    r = mid - 1;
                } else {
                    l = mid + 1;
                }
            } else {
                if (mountainArr.get(mid) > target) {
                    l = mid + 1;
                } else {
                    r = mid - 1;
                }
            }
        }
        return -1;
    }

数组处理

2、给一个数组,其中数字0移动到数组末尾,非0数字顺序不变,要求时间复杂度O(n),空间复杂度O(1),如[1,0,3,5,0,0,17,0,8,0] 处理为:[1,3,5,17,8,0,0,0,0,0]。

整体思路

双指针法,左指针指向第一个为0数字,右指针指向左指针后边第一个非0数字,交换,之后呢左右指针指向的和最初含义就反了,左右指针进行交换,右指针继续找下个非0数字。

代码实现

    public static void fun(int[] arr) {
        int l = 0, r = 0;

        while (r < arr.length) {
            while (l < arr.length && arr[l] != 0) {
                l++;
            }
            if (l == arr.length) {
                break;
            }
            r = Math.max(r, l + 1);
            while (r < arr.length && arr[r] == 0) {
                r++;
            }
            if (r == arr.length) {
                break;
            }
            // 交换左右指针指向的元素
            int t = arr[r];
            arr[r++] = arr[l];
            arr[l++] = t;
        }
    }
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值