算法分享系列No.8--(大厂面试实际场景算法题)---找零钱 问题

一、该类题目---基础信息列表&背景


大厂面试算法题,为了显示高逼格,显示高档次,经常跟实际问题相结合(如 股票买卖/ 找零钱问题/ 汽油问题 / 打家劫舍 / 分糖果 / 岛屿问题 ),想要考察面试人,从实际问题转化成熟悉的解题模型,灵活运用能力。近期问了些面试字节的朋友,30%都考到了股票。本次这类题型的梳理,也是对自己解决这类算法的一个总结。

  1. 题目难易分类【easy】【middle】【hard】
  2. 题目频率(牛客有考察次数)【高频】(10<=考察次数) 【中频】(2 <=考察次数 < 10) 【普通】

1-1、题目列表(按照两个平台输出,LeetCode 和 牛客)

实际问题刷题平台 & 题序号 & 题目难易度 & 考察频次

找零钱

【数组】

【动态规划】

LeetCode(题目难易度---出现频率)

322. 零钱兑换【middle】-----72.24%

518. 零钱兑换 II【middle】-----55.95%

860. 柠檬水找零【easy】-----40.00%

牛客【题库--算法篇--面试高频榜单】

NC126 兑换零钱(一)【middle】【中频】----- 动态规划

NC203 兑换零钱(二)【middle】【普通】----- 数组,动态规划

大厂面试算法题---实际场景高逼格解决思路总结----股票买卖系列 问题(以及相关打家劫舍问题)全解析_安吉_lh1029的博客-CSDN博客

1-2、题型分析

找零钱【数组】【动态规划】

动态规划(Dynamic Programming,DP)是运筹学的一个分支,是求解决策过程最优化的过程。

动态规划算法通常用于求解具有某种最优性质的问题。在这类问题中,可能会有许多可行解。每一个解都对应于一个值,我们希望找到具有最优值的解。动态规划算法与分治法类似,其基本思想也是将待求解问题分解成若干个子问题,先求解子问题,然后从这些子问题的解得到原问题的解。

动态规划具备的特征:最优子结构性质,无后效性,子问题的重叠性

局限性:动态规划对于解决多阶段决策问题的效果是明显的,但是动态规划也有一定的局限性。首先,它没有统一的处理方法,必须根据问题的各种性质并结合一定的技巧来处理;另外当变量的维数增大时,总的计算量及存贮量急剧增大。因而,受计算机的存贮量及计算速度的限制,当今的计算机仍不能用动态规划方法来解决较大规模的问题,这就是“维数障碍”。

二、【兑换零钱】问题具体分析

2-1、兑换零钱问题(一)

(1)题目描述

(2)解题思路---动态规划

具体做法:

  • step 1:可以用dp[i] 表示要凑出i元钱需要最小的货币数。
  • step 2:一开始都设置为最大值aim+1 ,因此货币最小1元,即货币数不会超过aim 
  • step 3:初始化dp[0]=0。
  • step 4(难点,找到转移递推公式):后续遍历1元到aim元,枚举每种面值的货币都可能组成的情况,取每次的最小值即可,转移方程为 dp[i]=min(dp[i],dp[i−arr[j]]+1)
  • step 5:最后比较dp[aim] 的值是否超过aim,如果超过说明无解,否则返回即可。

(3)、具体代码实现如下:

import java.util.*;

public class Solution{

    public int minMoney(int[] arry, int aim){
        int len = arry.length;
        if(len == 0) return -1;
        if(aim == 0) return 0;
        
        //初始化数据,并进行辅助空间赋值
        int Max = aim+1;
        int[] dp = new int[Max];
        Arrays.fill(dp,Max);
        //目前为0元时,自然没有对应货币数
        dp[0] = 0;
        //遍历dp,目前金钱数
        for(int i =1 ; i < Max; i++){
           //遍历钱币
           for(int j = 0; j< len; j++){
               //当前钱币数比目标aim资金小,就可以进行分配
               if(arry[j] <= i){
                   dp[i] = Math.min(dp[i-arry[j]]+1, dp[i]);
               }
              
           }
        }
        return dp[aim] > aim ? -1: dp[aim];
    }

}

------------------------------

如果对上面思路已经很清晰了,可以跳过这里,帮助辅助理解,相关输出打印

//测试案例

int[] prices = {5,2,3};

int k = 20;

minMoney(prices,20);

兑换零钱dp[]数组遍历输出过程

开始运行...

 for遍历前 0 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21 

 for遍历中 i=1, j=0 0 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21 

 for遍历中 i=1, j=1 0 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21 

 for遍历中 i=1, j=2 0 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21 

 for遍历中 i=2, j=0 0 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21 

 for遍历中 i=2, j=1 0 21 1 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21 

 for遍历中 i=2, j=2 0 21 1 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21 

 for遍历中 i=3, j=0 0 21 1 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21 

 for遍历中 i=3, j=1 0 21 1 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21 

 for遍历中 i=3, j=2 0 21 1 1 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21 

 for遍历中 i=4, j=0 0 21 1 1 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21 

 for遍历中 i=4, j=1 0 21 1 1 2 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21 

 for遍历中 i=4, j=2 0 21 1 1 2 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21 

 for遍历中 i=5, j=0 0 21 1 1 2 1 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21 

 for遍历中 i=5, j=1 0 21 1 1 2 1 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21 

 for遍历中 i=5, j=2 0 21 1 1 2 1 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21 

 for遍历中 i=6, j=0 0 21 1 1 2 1 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21 

 for遍历中 i=6, j=1 0 21 1 1 2 1 3 21 21 21 21 21 21 21 21 21 21 21 21 21 21 

 for遍历中 i=6, j=2 0 21 1 1 2 1 2 21 21 21 21 21 21 21 21 21 21 21 21 21 21 

 for遍历中 i=7, j=0 0 21 1 1 2 1 2 2 21 21 21 21 21 21 21 21 21 21 21 21 21 

 for遍历中 i=7, j=1 0 21 1 1 2 1 2 2 21 21 21 21 21 21 21 21 21 21 21 21 21 

 for遍历中 i=7, j=2 0 21 1 1 2 1 2 2 21 21 21 21 21 21 21 21 21 21 21 21 21 

 for遍历中 i=8, j=0 0 21 1 1 2 1 2 2 2 21 21 21 21 21 21 21 21 21 21 21 21 

 for遍历中 i=8, j=1 0 21 1 1 2 1 2 2 2 21 21 21 21 21 21 21 21 21 21 21 21 

 for遍历中 i=8, j=2 0 21 1 1 2 1 2 2 2 21 21 21 21 21 21 21 21 21 21 21 21 

 for遍历中 i=9, j=0 0 21 1 1 2 1 2 2 2 3 21 21 21 21 21 21 21 21 21 21 21 

 for遍历中 i=9, j=1 0 21 1 1 2 1 2 2 2 3 21 21 21 21 21 21 21 21 21 21 21 

 for遍历中 i=9, j=2 0 21 1 1 2 1 2 2 2 3 21 21 21 21 21 21 21 21 21 21 21 

 for遍历中 i=10, j=0 0 21 1 1 2 1 2 2 2 3 2 21 21 21 21 21 21 21 21 21 21 

 for遍历中 i=10, j=1 0 21 1 1 2 1 2 2 2 3 2 21 21 21 21 21 21 21 21 21 21 

 for遍历中 i=10, j=2 0 21 1 1 2 1 2 2 2 3 2 21 21 21 21 21 21 21 21 21 21 

 for遍历中 i=11, j=0 0 21 1 1 2 1 2 2 2 3 2 3 21 21 21 21 21 21 21 21 21 

 for遍历中 i=11, j=1 0 21 1 1 2 1 2 2 2 3 2 3 21 21 21 21 21 21 21 21 21 

 for遍历中 i=11, j=2 0 21 1 1 2 1 2 2 2 3 2 3 21 21 21 21 21 21 21 21 21 

 for遍历中 i=12, j=0 0 21 1 1 2 1 2 2 2 3 2 3 3 21 21 21 21 21 21 21 21 

 for遍历中 i=12, j=1 0 21 1 1 2 1 2 2 2 3 2 3 3 21 21 21 21 21 21 21 21 

 for遍历中 i=12, j=2 0 21 1 1 2 1 2 2 2 3 2 3 3 21 21 21 21 21 21 21 21 

 for遍历中 i=13, j=0 0 21 1 1 2 1 2 2 2 3 2 3 3 3 21 21 21 21 21 21 21 

 for遍历中 i=13, j=1 0 21 1 1 2 1 2 2 2 3 2 3 3 3 21 21 21 21 21 21 21 

 for遍历中 i=13, j=2 0 21 1 1 2 1 2 2 2 3 2 3 3 3 21 21 21 21 21 21 21 

 for遍历中 i=14, j=0 0 21 1 1 2 1 2 2 2 3 2 3 3 3 4 21 21 21 21 21 21 

 for遍历中 i=14, j=1 0 21 1 1 2 1 2 2 2 3 2 3 3 3 4 21 21 21 21 21 21 

 for遍历中 i=14, j=2 0 21 1 1 2 1 2 2 2 3 2 3 3 3 4 21 21 21 21 21 21 

 for遍历中 i=15, j=0 0 21 1 1 2 1 2 2 2 3 2 3 3 3 4 3 21 21 21 21 21 

 for遍历中 i=15, j=1 0 21 1 1 2 1 2 2 2 3 2 3 3 3 4 3 21 21 21 21 21 

 for遍历中 i=15, j=2 0 21 1 1 2 1 2 2 2 3 2 3 3 3 4 3 21 21 21 21 21 

 for遍历中 i=16, j=0 0 21 1 1 2 1 2 2 2 3 2 3 3 3 4 3 4 21 21 21 21 

 for遍历中 i=16, j=1 0 21 1 1 2 1 2 2 2 3 2 3 3 3 4 3 4 21 21 21 21 

 for遍历中 i=16, j=2 0 21 1 1 2 1 2 2 2 3 2 3 3 3 4 3 4 21 21 21 21 

 for遍历中 i=17, j=0 0 21 1 1 2 1 2 2 2 3 2 3 3 3 4 3 4 4 21 21 21 

 for遍历中 i=17, j=1 0 21 1 1 2 1 2 2 2 3 2 3 3 3 4 3 4 4 21 21 21 

 for遍历中 i=17, j=2 0 21 1 1 2 1 2 2 2 3 2 3 3 3 4 3 4 4 21 21 21 

 for遍历中 i=18, j=0 0 21 1 1 2 1 2 2 2 3 2 3 3 3 4 3 4 4 4 21 21 

 for遍历中 i=18, j=1 0 21 1 1 2 1 2 2 2 3 2 3 3 3 4 3 4 4 4 21 21 

 for遍历中 i=18, j=2 0 21 1 1 2 1 2 2 2 3 2 3 3 3 4 3 4 4 4 21 21 

 for遍历中 i=19, j=0 0 21 1 1 2 1 2 2 2 3 2 3 3 3 4 3 4 4 4 5 21 

 for遍历中 i=19, j=1 0 21 1 1 2 1 2 2 2 3 2 3 3 3 4 3 4 4 4 5 21 

 for遍历中 i=19, j=2 0 21 1 1 2 1 2 2 2 3 2 3 3 3 4 3 4 4 4 5 21 

 for遍历中 i=20, j=0 0 21 1 1 2 1 2 2 2 3 2 3 3 3 4 3 4 4 4 5 4 

 for遍历中 i=20, j=1 0 21 1 1 2 1 2 2 2 3 2 3 3 3 4 3 4 4 4 5 4 

 for遍历中 i=20, j=2 0 21 1 1 2 1 2 2 2 3 2 3 3 3 4 3 4 4 4 5 4 

 for遍历后 0 21 1 1 2 1 2 2 2 3 2 3 3 3 4 3 4 4 4 5 4 

运行结束。

三、【加油站】问题具体分析

3-1、加油站问题描述

 具体代码实现:

import java.util.*;
public class Solution {
    /**
     * @param gas int整型一维数组 
     * @param cost int整型一维数组 
     * @return int整型
     */
    public int gasStation (int[] gas, int[] cost) {
        //加油站个数
        int n = gas.length;
        //汽车油量剩余
        int rest = 0;
        //起始位置start, sum表示走完一圈后剩余油量
        int start = 0, sum = 0;
        for(int i = 0; i < n; i++){
            rest += gas[i]-cost[i];
            sum +=gas[i]-cost[i];
            //如果剩余油量不足,则更换起始位置
            if(rest < 0){
                start = (i+1)% n;
                rest = 0;
            }
        }
        return sum>=0?start:-1;
    }
}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值