字节面试题:小于n的最大数(Java)仅供学习参考

字节面试题:小于n的最大数(Java)

  • 问题:给定一个数n如23121,给定一组数字arr如[2 4 9],求由a中元素组成的小于n的最大数
  • 思路1:经典回溯,按arr回溯
  • 解题代码
// done by wjy 2024-7-12
import java.util.Scanner;

public class maxVal {
    static int[] arr;
    static int res;
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        int n = sc.nextInt();
        int arrLen = sc.nextInt();
        arr = new int[arrLen];
        for(int i = 0; i < arrLen; i++){
            arr[i] = sc.nextInt();
        }
        // arr [2 4 6]
        backtrace(0, 0, n);
        System.out.println(res);
    }

    public static void backtrace(int len, int path, int n){
        if(path >= n){
            return;
        }
        res = Math.max(path, res);
        for(int i = 0; i < arr.length; i++){
            int nowValue = arr[i];
            int path1 = path * 10 + nowValue;
            backtrace(len + 1, path1, n);
        }
    }

}

  • 思路2:  对n的每一位进行扫描,首先要判断是否到达最后一位,末位需要特殊处理
          对于之前位:
              1、如果arr中包含n当前位的值,直接取,进入下层
              2、如果arr中都小于当前位的值,直接取最大,回溯上层
              3、如果在回溯阶段,如果在当前位能找到小于当前值的最大值,那么直接取,替换当前位后返回。如果找不到,继续向前回溯,如果回溯到bit = -1并且处于回溯状态,那么直接取位数-1的arr中最大数组成的值(这里使用state = 1表明正在回溯)
          对于最后位:
              1、arr中有当前值,那么直接取位数-1的arr中最大数组成的值(9999)
              2、arr中无当前值,但有小于当前值,直接取小于当前值的最大值
              3、arr中无当前值,也无小于当前值,那就回溯上层
         
          终止条件:1、回溯到开头,并且仍需回溯 2、末尾处理完毕
  • 解题代码
// done by wjy 2024-7-12
// 仅供学习参考

import java.util.ArrayList;
import java.util.Scanner;
import java.util.List;
//(java)最大数(给定一个数n如23121,给定一组数字a如[2 4 9]求由a中元素组成的小于n的最大数)

//5位
//第1位直接取2
//第2位没有,直接取2
//第3、4、5位直接取9

//21121 [2 4 9]
//第1位取2
//第2位取不了,填9,回溯到前一位,发现取不了,直接上4位最大

//22222 [2 4 9]
//第5位直接取9,回溯到第4位取9,回溯到第3位取9,回溯到第2位取9,回溯到第1位取不了,只能上4位最大

public class maxValue {
    static int[] tmp;
    static int bitNum;
    static int[] arr;
    static int[] nums;
    static int ans;
    static int maxNum;
    static int minNum;
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        int n = sc.nextInt();
        int arrLen = sc.nextInt();
        arr = new int[arrLen];
        for(int i = 0; i < arrLen; i++){
            arr[i] = sc.nextInt();
            maxNum = Math.max(maxNum, arr[i]);
            minNum = Math.min(minNum, arr[i]);
        }
        bitNum = judgeBit(n);
        tmp = new int[bitNum];
        nums = new int[bitNum];
        int num1 = n;
        int i = 0;
        while(num1 > 0){
            int t = num1 % 10;
            nums[bitNum - 1 - i] = t;
            i++;
            num1 /= 10;
        }
//        for(int j = 0; j < bitNum; j++){
//            System.out.println(nums[j]);
//        }
        // 如果首位比最小值还小,那么直接bit - 1全取最大
        if(nums[0] < minNum){
            for(int k = 0; k < bitNum - 1; k++){
                ans = maxNum * 10 + maxNum;
            }
        }else{
            backtrace(n, 0,0, 0);
        }
        System.out.println(ans);
    }

    //回溯是因为,如果n的当前位小于所有nums中的数,那么必须返回上一位,取小于n上一位的最大值,如果取不了,那么继续返回上一位
    public static void backtrace(int target, int bit, int now, int state){
        // 处理第bit位
        // 能取先取,取不了找最大的

        System.out.println("当前位数是: " + bit + "当前状态是: " + state);
        // 两种结束条件,一种回溯回来,一种处理完毕
        if(bit == -1 && state == 1){
            ans = now;
            return;
        }

        // 重新整理思路
        // 如果在向后寻找
        if(state == 0){
            // 处理最后一位
            System.out.println("向后扫描阶段");
            if(bit == bitNum - 1){
                // 找到小于它的最大数
                System.out.println("处理最后一位");
                int res = -1;
                for(int i = 0; i < arr.length; i++){
                    if(arr[i] < nums[bit]){
                        res = Math.max(res, arr[i]);
                    }
                }
                if(res != -1){
                    ans =  now * 10 + res;
                    return;
                }else{
                    // 直接bitNum - 1位最大值
                    int value = 0;
                    for(int i = 0; i < bitNum - 1; i++){
                        value = value * 10 + maxNum;
                    }
                    System.out.println("value: " + value);
                    ans = value;
                    return;
                }
            }else{
                // 找到小于等于它的最大数
                int res = 0;
                for(int i = 0; i < arr.length; i++){
                    if(arr[i] <= nums[bit]){
                        res = Math.max(res, arr[i]);
                    }
                }
                // 如果是等于,那么继续往后扫描
                System.out.println("res = " + res);
                if(res == nums[bit]){
                    System.out.println("等于,向后扫描 " + res);
                    backtrace(target, bit + 1, now * 10 + res, 0);
                }else if(res < nums[bit]){
                    System.out.println("向后扫描,准备回溯,因为最大数是小于不是等于");
                    // 如果是小于,那么回溯,后面的bit全是最大数
                    // 23121 [2 4 9] now = 2
                    now = now * 10 + res; // now = 22
                    // 接下来需要变成22999
                    System.out.println("now = " + now);
                    int behindBit = bitNum - bit - 1;
                    System.out.println("behindBit = " + behindBit);
                    int incr = 0;
                    for(int i = 0; i < behindBit; i++){
                        incr = incr * 10 + maxNum;
                    }
                    for(int i = 0; i < behindBit; i++){
                        now = now * 10;
                    }
                    System.out.println("now = " + now);
                    System.out.println("incr = " + incr);
                    backtrace(target, bit - 1, now + incr, 1);
                }
            }
        } else{
            System.out.println("向前扫描阶段");
            // state = 1 向前回溯 41999 [2 4 9] 就得29999
            // 先找arr中有没有比nums小的,如果有就直接算,如果没有还得往前回溯
            // 找到小于它的最大数
            int res = -1;
            for(int i = 0; i < arr.length; i++){
                if(arr[i] < nums[bit]){
                    res = Math.max(res, arr[bit]);
                }
            }
            if(res != -1){
                // 有,就直接算,比如23124 [2 4 9] 23199 -> 22199 只替换当前位,替换成res
                int wei = now;
                for(int i = 0; i < bitNum - bit - 1; i++){
                    wei /= 10;
                }
                wei = wei % 10;
                int incr = nums[bit];
                for(int i = 0; i < bitNum - bit - 1; i++){
                    wei *= 10;
                    incr *= 10;
                }
                now = now - wei + incr;
                ans = now;
                return;
            }else{
                System.out.println("向前扫描" + res);
                backtrace(target, bit - 1, now, 1);
            }
        }
    }

    public static int judgeBit(int num){
        int i = 0;
        while(num > 0){
            int t = num % 10;
            num /= 10;
            i++;
        }
        return i;
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值