查找最接近的元素

题目描述详见http://noi.openjudge.cn/ch0111/01/。注意,需要通过二分查找算法实现。
查找最接近元素
题目描述详见http://noi.openjudg0e.cn/ch0111/01。
【解题思路】:使用二分查找,每次折半找到中间元素,和value作差,取绝对值,即为距离。注意事项:需要处理左边界情况,右边界情况,后几位重复,
【程序代码】:详见如下代码。

package com.demo.course.mid.problem03;

import java.util.Scanner;

/**
 * author: nitaotao
 * date: 2021/12/21 13:42
 * version: 1.0
 * description: http://noi.openjudge.cn/ch0111/01
 */
public class Main {
    public static void main(String[] args) {
        Main main = new Main();
        Scanner scanner = new Scanner(System.in);
        int n = scanner.nextInt(); //非降序列长度
        int[] data = new int[n]; //非降序列
        for (int i = 0; i < n; i++) {
            data[i] = scanner.nextInt();
        }
        int m = scanner.nextInt(); //要询问的给定值个数
        int[] selectNum = new int[m];
        for (int i = 0; i < m; i++) {
            selectNum[i] = scanner.nextInt();
        }
        for (int i = 0; i < selectNum.length - 1; i++) { //从查找数组中取出元素进行查询
            System.out.println(main.binarySearch(data, selectNum[i]));
        }
        System.out.print(main.binarySearch(data, selectNum[selectNum.length - 1]));

    }

    /**
     * binarySearch 二分查找最近元素
     *
     * @param arr
     * @param value 总体思路,使用二分查找,每次折半找到中间元素,和value作差,取绝对值,即为距离
     */
    public int binarySearch(int[] arr, int value) {
        //处理单值数组情况
        if (arr.length == 1) {
            return arr[0];
        }
        //处理左边界情况
        if (value <= arr[0]) {
            return arr[0];
        } else if (value >= arr[arr.length - 1]) {
            //处理右边界情况
            //判断后几位是否相等
            int index = arr.length - 1;
            int distant = arr[index] - value;
            while (distant == arr[arr.length - 1] - value || index == 0) {
                //最后一位往前移
                index--;
                //如果变化,则跳出循环
                distant = arr[index] - value;
            }
            index++;
            return arr[index];
        }
        int start = 0; //起始位置
        int end = arr.length - 1; //结束位置
        while (true) {
            int mid = (start + end) / 2; //计算中间位置下标
            int midValue = arr[mid]; //中间值
            int distance = midValue - value; //距离
            if (distance == 0) {
                //System.out.println("距离最近为:" + distance + "-----最近中间值:" + midValue);
                // 若有多个值满足条件,输出最小的一个
                for (int i = 0; i < arr.length; i++) {
                    if (arr[i] - value == 0) {
                        //如果距离为0,返回中间值
                        return arr[i];
                    }
                }
            } else {
                //如果是正数,说明待查找数值比中间数值小,即待查找数值在数轴中间位置左边,则需要将end=mid-1
                if (distance > 0) {
                    end = mid - 1;
                } else {
                    //如果是负数,说明待查找数值比中间数值大,即待查找数值在数轴中间位置右边,则需要将start=mid+1
                    start = mid + 1;
                }
            }
            if (start > end) {
                int startDistance = Math.abs(arr[start] - value);
                int endDistance = Math.abs(arr[end] - value);
                if (startDistance == endDistance) {
                    return arr[end]; //此时start>end,选较小的
                } else {
                    return startDistance < endDistance ? arr[start] : arr[end];
                }
            }
        }
    }
}

【运行结果】:详见如下截图。

图13 查找最接近元素程序运行结果
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值