当前位置: 首页 > news >正文

字节手撕题 小于 n 的最大整数 贪心 回溯 剪枝 全排列

给定一个数字字符串S和一个数组nums,数组中的元素都在0~9之间,问从数组中选择元素组成的数字,小于N的最大值是多少?
例如:S = “24378”,nums:{2,3,9},组成的最大值为23999。

👨‍🏫 参考视频

import java.util.Arrays;

public class Main {

    public static void main(String[] args) {
        /*
        示例 1:A={1, 2, 9, 4},n=2533,返回 2499。

        示例 2:A={1, 2, 5, 4},n=2543,返回 2542。

        示例 3:A={1, 2, 5, 4},n=2541,返回 2525。

        示例 4:A={1, 2, 9, 4},n=2111,返回 1999。

        示例 5:A={5, 9},n=5555,返回 999。
         */

        // 示例1
        int[] a1 = {1, 2, 9, 4};
        int n1 = 2533 ;
        System.out.println("示例1:" +Arrays.toString(a1)+"," + n1 + " : "+ getMaxLessNum(a1, n1) + " (应返回2499)");

        // 示例2
        int[] a2 = {1, 2, 5, 4};
        int n2 = 2543;
        System.out.println("示例2:" +Arrays.toString(a2)+"," + n2 + " : "+ getMaxLessNum(a2, n2) + " (应返回2542)");

        // 示例3
        int[] a3 = {1, 2, 5, 4};
        int n3 = 2541;
        int m = 2541;

        System.out.println("示例3:" +Arrays.toString(a3)+"," + n3 + " : "+ getMaxLessNum(a3, n3) + " (应返回2525)");

        // 示例4
        int[] a4 = {1, 2, 9, 4};
        int n4 = 2111;
        System.out.println("示例4:" +Arrays.toString(a4)+"," + n4 + " : "+ getMaxLessNum(a4, n4) + " (应返回1999)");

        // 示例5
        int[] a5 = {5, 9};
        int n5 = 5555 ;
        System.out.println("示例5:" +Arrays.toString(a5)+"," + n5 + " : " + getMaxLessNum(a5, n5) + " (应返回999)");

        int[] a6 = {5};
        int n6 = 2 ;
        System.out.println("示例6:" +Arrays.toString(a6)+"," + n6 + " : "+ getMaxLessNum(a6, n6) + " (不存在)");
    }

    static int[] nums;

    /**
     * 获取由数组nums中的元素组成的数字,且小于n的最大值
     */
    public static String getMaxLessNum(int[] a, int b) {
        // 对nums数组进行排序,方便后续查找最大值
        nums = a;
        Arrays.sort(nums);
        int[] n = String.valueOf(b).chars().map(c -> c - '0').toArray();
        // 用于存储结果数字的字符串
        // 深度优先搜索,寻找最大值
        StringBuilder ans = new StringBuilder();
        dfs(true, ans,n, 0);

        return ans.length() == 0 ? "不存在" :ans.toString();
    }
 
    /**
     * 深度优先搜索,寻找最大值
     * @param equal:
     *              true 表示前面的都相等
     *              false 表示前面有小于 nums 的位后面都可以取最大
     * @param n 表示的是最大数
     * @param idx 表示最大数枚举到的下标
     */
    private static boolean dfs(boolean equal, StringBuilder ans, int[] n,  int idx) {
        // 如果是最后一位,则需要判定是否有小于n的数
        if (idx == n.length - 1) {
            if (!equal) {
                // 如果前面已经有不相等的位,则直接取nums的最大值
                ans.append(nums[nums.length - 1]);
                return true;
            } else { // 说明前面的数位都相等,当前数位必须取一个小于 n 对应数位的值,找不到返回 false
                // 否则需要寻找小于n最后一位的最大值
                for (int i = nums.length - 1; i >= 0; i--) {
                    if (nums[i] < n[n.length - 1]) {
                        ans.append(nums[i]);
                        return true;
                    }
                }
                return false;
            }
        }

        // 前面有不相等的,后面都取nums的最大值即可
        if (!equal) {
            for (int i = idx; i < n.length; i++) {
                ans.append(nums[nums.length - 1]);
            }
            return true;
        }

        // 前面都相等,优先取和n[idx]相同的值(因为高位大才是真的大),深度优先遍历,如果后面组成的数小于n,则找到了最大的值。
        // 如果当前值小于n[idx],则后面都取nums的最大值即可
        for (int i = nums.length - 1; i >= 0; i--) {
            if (nums[i] == n[idx]) {
                ans.append(nums[i]);
                boolean result = dfs(true,ans, n, idx + 1);
                if (result) {
                    return true;
                } else {
                    ans.deleteCharAt(ans.length() - 1); // 回溯,删除最后一个字符
                }
            }

            if (nums[i] < n[idx]) {
                ans.append(nums[i]);
                dfs(false,ans, n, idx + 1); // 后续位都取最大值
                return true;
            }
        }

        // 神之一笔,所有都不满足,直接取减少一位
        // 如果前面都不满足,删除第一位即可
        if (idx == 0) {
            dfs(false,ans,  n, idx + 1);
            return true;
        }

        return false;
    }
}

👨‍🏫 参考博客

相关文章:

  • 基于springboot的地方美食分享网站(全套)
  • 基于Flux模型的多模态可控图像生成工作流实践
  • 从零开始上手huggingface
  • 综合实验配置
  • 开源链动2+1模式、AI智能名片与S2B2C商城小程序源码在社交电商渠道拓宽中的协同应用研究
  • Linux 账号和权限管理命令选项解释
  • 深度学习——图像相似度评价指标
  • busybox的终端图形化界面菜单
  • 电缆接地电流监测系统,为电力稳定运行保驾护航
  • Linux进程间通信
  • 《Java到Go的平滑转型指南》
  • HTML CSS JS官方文档
  • Camera2 实现重力感应四个方向调试相机预览
  • [学习笔记] VM虚拟机安装Ubuntu系统
  • SpringMVC_day02
  • 【清华大学】AIGC发展研究(3.0版)
  • ROS导航工具包Navigation
  • Scikit-learn模型评估全流程解析:从数据划分到交叉验证优化
  • Java-模块二-2
  • 【MySQL】从零开始:掌握MySQL数据库的核心概念(三)
  • 巴菲特最新调仓:一季度大幅抛售银行股,再现保密仓位
  • 中国军网:带你揭开3所新调整组建军队院校的神秘面纱
  • 湖北宜化拟斥资超32亿加价回购“弃子”,布局上游煤炭业务
  • 今年有望投产里程已近3000公里,高铁冲刺谁在“狂飙”?
  • 商务部就开展加强战略矿产出口全链条管控工作应询答记者问
  • 微软将在全球裁员6000人,目标之一为减少管理层