字节面试题:小于n的最大数(Java)
- 问题:给定一个数n如23121,给定一组数字arr如[2 4 9],求由a中元素组成的小于n的最大数
- 思路1:经典回溯,按arr回溯
- 解题代码
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();
}
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、末尾处理完毕 - 解题代码
import java.util.ArrayList;
import java.util.Scanner;
import java.util.List;
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;
}
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);
}
public static void backtrace(int target, int bit, int now, int state){
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{
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("向后扫描,准备回溯,因为最大数是小于不是等于");
now = now * 10 + res;
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("向前扫描阶段");
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){
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;
}
}