面试算法题记录

这篇博客记录了一道面试算法题,要求从给定数组中选取元素组成小于指定数n的最大数。解决方案采用了贪心、回溯和二分算法。首先对数组排序,然后分解n为列表,根据位数进行操作。如果数组最大值大于n的位数,则直接选取最大值;否则,通过回溯找到合适的组合。代码实现包括主要函数和辅助函数,并附带测试用例及输出结果。
摘要由CSDN通过智能技术生成

面试算法题

题目

给一个数组nums=[5,4,8,2],给一个n=5416, 让你从nums中选出一些元素,使得组成的数字是小于n的最大数。

代码解析思路

该题使用到的算法主要是贪心、回溯以及二分,首先将nums数组进行排序方便进行二分查找,之后将给定数字n分解成一个列表,注意最高位在列表的最后一位,需要从前往后尽心寻找。

首先判断能取的最大数跟N的位数是否相同,不同直接取数组中的最大值即可。
注意如果出现前面取跟n一样的数,而后面出现没有数可以取的情况需要回溯减小前面的数。

代码

package com.byte_mianshi;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Scanner;
public class Nmin {
    private  static int ret = 0;
    private  static  boolean over = false;
    public static void resolve(int n,int[] data){
        Arrays.sort(data);
        List<Integer> list = new ArrayList<Integer>();
        int n_copy = n;
        int tmp = 0;
        while (n_copy >0){
            tmp = n_copy % 10;
            n_copy = n_copy / 10;
            list.add(tmp);
        }
        System.out.println("数据打印开始");

        for (int d: list) {
            System.out.println(d);
        }
        System.out.println("数据打印开始");
        System.out.println("数组打印开始");
        for(int d : data){
            System.out.println(d);
        }
        System.out.println("数组打印完毕");
        System.out.println("数据大小:" + list.size());


        int minData = 0;
        for (int d: list) {
            minData = minData * 10 + data[0];
        }
        System.out.println("最小值"+minData);
        if(minData >= n){
            //只能取比n少一位
            dfs(data,list,n,list.size()-2,0,true);
        }else{
            dfs(data,list,n,list.size()-1,0,false);
        }

        System.out.println(ret);
    }

    /**
     *
     * @param data  可选数组数据
     * @param list  分解后的n值
     * @param n
     * @param index  当前正在选择的位数
     * @param ans    已经选择的数组成的值
     * @param flag   是否可以无脑选择最大数的标志位
     */
    public static  void dfs(int[] data,List<Integer> list,int n,int index,int ans,boolean flag){
        int len = list.size();
        if(over == true){
            return ;
        }
        if(index < 0){
            //选择完毕
            if(ans < n){
                ret = Math.max(ret,ans);
                over = true;
                return ;
            }
            return ;
        }
        if(flag == false){
            //找到最大的不大于list.get(index)的坐标
            int  f = find(list.get(index) , data);
            //当前所有的数都比需要小于的数大,说明前面的数取大了,直接返回
            if( f < 0){
                return;
            }else{
                for(int i = f;i>=0;i--){
                    ans = ans * 10 + data[i];
                    if(data[i] < list.get(index)){
                        flag = true;
                        dfs(data,list,n,index-1,ans,flag);
                    }else{
                        //相等的情况
                        dfs(data,list,n,index-1,ans,flag);
                    }
                    ans = (ans - data[i])/10;
                }
            }
        }else{
            //说明前面有数字比n对应的数字小,可以一直取最大值
            ans = ans * 10 + data[data.length-1];
            dfs(data,list,n,index-1,ans,flag);
        }

    }

    /**
     * 找到不大于min的第一个序列号
     * @param min
     * @param data  查找的数组
     * @return   数组中第一个小于等于min的序号
     */
    public static int find(int min,int[] data){
        int left  = 0;
        int right = data.length-1;
        while (left <= right){
            int mid = left + ((right - left)>>1);
            if( data[mid] <= min){
                left = mid + 1;
            }else{
                right = mid - 1;
            }
        }
        if( right <0 ){
            return -1;
        }
        return right;

    }
}

测试案例

public class NminTest {

    @Test
    public void Test(){
        Nmin nmin = new Nmin();
        int[] data = new int[] {5,6,7,8};
        nmin.resolve(2333,new int[]{2,3});
        nmin.resolve(233332,new int[]{2,3});
        nmin.resolve(500,new int[]{4,9});
        nmin.resolve(5612,new int[] {5,6,7,8});
        nmin.resolve(5416,new int[] {5,4,8,2});
        nmin.resolve(123434,new int[] {1,4,6,3,8});
        nmin.resolve(32,new int[] {2,3});
    }

}

输出结果

2332
233323
499
5588
5288
118888
23

Process finished with exit code 0

注意:不保证能够通过所有的测试案例

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值