算法题目:小于n的最大数

该博客介绍了一种算法问题,即如何从给定数组中选取元素,使得这些元素组合成的数字小于指定数n且尽可能大。通过贪心策略和二分搜索,作者提供了详细的解决方案,包括如何确定目标最大值,如何进行二分查找以及如何构建最终的数字。示例代码展示了如何应用这些方法解决具体问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

算法题目:小于n的最大数
问题描述:给一个数组nums=[5,4,8,2],给一个n=5416, 让你从nums中选出一些元素,使得组成的数字是小于n的最大数,比如这个例子应该返回5288
思想:贪心+二分

package 补充题目;

import java.util.Arrays;

/**
 * description:code
 *
 * @author xiaozhenzhen001
 * @date 2022/6/13
 */
public class 小于n的最大数 {

    public static void main(String[] args) {

        int[] nums = new int[]{4, 5};
        System.out.println(build(4413, nums));

    }

    public static int build(int num, int[] arr) {
        Arrays.sort(arr);
        //查找目标最大值为 num-1 or 减一位后的最小值,
        String maxStr = getFindMaxNum(num, arr[0]);
        char[] res = new char[maxStr.length() - 1];
        // 当前位真实数据与【maxStr当前位】比较,影响下一位数据的选择
        boolean preIndexLess = false;

        // key 贪心算法
        for (int i = 0; i < maxStr.length() - 1; i++) {
            // 要arr中的哪个位置数据,如果前一位比预期值小,则当前位可以取arr中最大值,否则二分查找
            int index = preIndexLess ? arr.length - 1 : search(maxStr, i, arr);
            // 赋值
            res[i] = (char) (arr[index] + '0');

            // 当前位真实数据与当前位比较,影响下一位数据的选择
            if (res[i] < maxStr.charAt(i)) {
                preIndexLess = true;
            }

        }
        return Integer.parseInt(new String(res));
    }

    /**
     * 获取要查找元素的最大值
     * minValue是数组中的最小值
     */
    public static String getFindMaxNum(int num, int minValue) {
        /**
         * 正常目标要找的最大值应是 num-1
         * 特殊:但有种情况不满足。这种情况拼不出来当前长度的数字,只能(长度-1)后的最大数
         * 如arr=[5, 4](最小值是4),num= 4413(最小值1) 。拼不出来(num-1),因为 4 < 1,所以查找的最大值应是 999 (num长度减一位后的最大值)
         */
        boolean flag = false;
        String numStr = String.valueOf(num);
        for (int i = 0; i < numStr.length(); i++) {
            if (minValue > (numStr.charAt(i) - '0')) {
                flag = true;
                break;
            }
        }

        int maxNum = flag ? (int) (Math.pow(10, (numStr.length() - 1)) - 1) : (num - 1);
        String maxStr = String.valueOf(maxNum);
        // 加一是为了方便最后一位的运算
        return maxStr + maxStr.charAt(maxStr.length() - 1);
    }

    /**
     * key 二分查找
     */
    public static int search(String str, int i, int[] arr) {
        // 1.确定当前位置的数据,选择的数与下一个数字有关(如,下一位数字比arr的最小值还小,说明只能当前位减一)
        int currentMaxNum = str.charAt(i) - '0';
        int arrMinNum = arr[0];
        int findNum = (str.charAt(i + 1) - '0') >= arrMinNum ? currentMaxNum : currentMaxNum - 1;
        // 2.使用二分法进行查找
        int left = 0, right = arr.length - 1;
        int index = -1;
        while (left <= right) {
            int middle = left + ((right - left) >> 1);
            if (arr[middle] == findNum) {
                index = middle;
                break;
            } else if (arr[middle] < findNum) {
                left = middle + 1;
            } else {
                right = middle - 1;
            }

        }
        // 3.找到就返回middle,否则返回right(arr[right]是比findNum小的最大值)
        // -1 表示表示arr中没有比findNum小的值
        return (index == (left + ((right - left) >> 1))) ? index : right;

    }
}

评论 8
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值