小米2019秋招面试算法题 最少立方数之和 dp与dfs解法

题目

最少立方数之和
链接:https://www.nowcoder.com/questionTerminal/4bc284dc9d0144628a722eb5d1191ef3?toCommentId=3672120

时间限制:C/C++ 1秒,其他语言2秒空间限制:C/C++ 64M,其他语言128M
算法知识视频讲解
给出一个数字N(0<N<1000000),将N写成立方数和的形式,求出需要的最少立方数个数。
例如N=17,1+8+8 = 17,最少需要3个立方数,则输出3。
N= 28,1+1+1+1+8+8+8=28, 需要7个立方数,1+27=28,需要2个立方数,所以最少立方数为2,则输出2。

输入描述:
一个数字N(0<N<1000000)

输出描述:
最少立方数个数
示例1
输入
28
输出
2

思路与代码

1.动态规划
借鉴至评论区
设dp[n]为组成 n需要的最少立方数个数
精髓所在:找的是所有差一步可以组成n的方案,求最小值加一;
dp[n] = 1 + min(dp[n-1],dp[n-8],dp[n-27],…) 要求n-iii>=0

import java.util.Scanner;
public class Main{
    public static void main(String[] args){
        Scanner input = new Scanner(System.in);
        int n = input.nextInt();
        int[] dp = new int[n+1];
        dp[0] = 0;dp[1] = 1;
        for(int i = 2;i<=n;i++){
            int min = Integer.MAX_VALUE;//用于保存最小的个数
            for(int j = 1;j*j*j<=i;j++){//找到最小的
                min = Math.min(min,dp[i-j*j*j]);
            }
            dp[i] = min + 1;
        }
         
        //
        System.out.println(dp[n]);
    }
}

2.dfs
首先生成小于N的立方数,存入集合中,接下来用N对集合中一个个立方数从大到小进行相减,最后如果刚好等于0,即成功,若不等于0则退出递归进行下一次循环。在递归中再加上判定统计立方数的数量是否大于目前最小立方数之和的剪枝操作。时间复杂度稍高,但是容易理解,也能通过所有测试用例

public class Main {
    static int min = Integer.MAX_VALUE;
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        int n = sc.nextInt();
         
        //把小于n的立方数装进集合
        List<Integer> al = new ArrayList<>();
        for (int i = 1; i < 100; i++) {
            if(Math.pow(i, 3)>n) {
                break;
            }else if (Math.pow(i, 3)==n) {
                System.out.println(1);
                return;
            }else {
                al.add((int)Math.pow(i, 3));
            }
        }
         
        int sum = 0;
        dfs(n,sum,al,al.size()-1);
        System.out.println(min);
   }
 
    private static void dfs(int n, int sum, ArrayList<Integer> al,int begin) {
        if(n==0) {//刚好够装,判定目前的总个数(sum)是否小于最小的,是的话min等于目前的sum
            if(sum<min) {
                min = sum;
            }
        }
        if(n<0||sum>min) {//n小于0,不够装  return    ||   使用次方数个数已经超过了目前最小的次方数    return
            return;
        }
        for (int i = begin; i >=0; i--) {
            dfs(n-al.get(i), sum+1, al, i);
        }
    }
 
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值