换零钱算法分析及代码示例

一 背景

求将1块钱换成为1角、2角、5角有多少种拆分方法是一个经典的递归求解问题。可以扩展到将任意一个整数拆分为几种个更小的整数,有几种拆分方式的求解问题。

 

二 分析

 基于这样一种分治思想:1块钱换1角,2角,5角的方式 = 1块钱换不包含第一种钱币的方法 + 1块钱换必包含第一种钱币的方法。从树型结构分析(下图以把3拆成1,2为例分析):

 

左子树描述的是不包含第一种钱币的拆分方式,减少的是钱币种类数;右子树表示的是必包含第一种钱币的拆分方法,减少的是钱币总量;辗转相减,当出现钱币总量为0时表示找到了一种拆分方式,当出现钱币总量为负或者类型列表为空表示未找到合适的拆分方式。

 

三 示例代码:

import java.util.LinkedList;
import java.util.Stack;

public class CSplit {
	public static void main(String[] args)
	{
		Stack<Integer> stSplitMethod = new Stack<Integer>();
		LinkedList<Integer> lstSplit = new LinkedList<Integer>();
		 
		//以将10拆分为1,2,5为例
		lstSplit.add(1);
		lstSplit.add(2);
		lstSplit.add(5);
		
		System.out.print("拆分方式如下:\n");
		CSplit split = new CSplit();
		Integer iNum = split.Split(stSplitMethod, 10, lstSplit, false);
		
		System.out.print("拆分方式数:\n");
		System.out.print(iNum);
	}
	
	//化整为零拆分函数,输出拆分方式的种类及拆分方法
	public Integer Split(Stack<Integer> stSplitMethod, Integer iTotal, 
			LinkedList<Integer> lstSplit, boolean bLOrR)
	{
		//右子树总量减去了第一个节点,压栈
		if(bLOrR && !lstSplit.isEmpty())
		{
			stSplitMethod.push(lstSplit.getFirst());
		}
		
		//辗转相减,iTotal为0说明找到一种拆分方式
		if(0 == iTotal)
		{
			System.out.print(stSplitMethod);
			System.out.print("\n");
			return 1;
		}
		
		if(iTotal < 0 || lstSplit.isEmpty())
		{
			return 0;
		}
		
		//拷贝一份,因为JAVA默认为传引用
		LinkedList<Integer> lstSplitTemp = new LinkedList<Integer>();
		lstSplitTemp.addAll(lstSplit);
		if(!lstSplitTemp.isEmpty())
		{
			lstSplitTemp.removeFirst();
		}
		
		//计算左子树即排除第一种类型的拆分方式 + 右子树即必含第一种类型的分类
		//方式
		Integer iNum = Split(stSplitMethod, iTotal, lstSplitTemp, false)
			+ Split(stSplitMethod, iTotal - lstSplit.getFirst(), lstSplit, true);
		
		//调用右子树拆分,执行了压载操作。无论是否找到合适的拆分方式都要出栈回退
		stSplitMethod.pop();
		
		return iNum;
	}
}


四 示例代码输出结果为:

拆分方式如下:
[5, 5]
[2, 2, 2, 2, 2]
[1, 2, 2, 5]
[1, 1, 2, 2, 2, 2]
[1, 1, 1, 2, 5]
[1, 1, 1, 1, 2, 2, 2]
[1, 1, 1, 1, 1, 5]
[1, 1, 1, 1, 1, 1, 2, 2]
[1, 1, 1, 1, 1, 1, 1, 1, 2]
[1, 1, 1, 1, 1, 1, 1, 1, 1, 1]
拆分方式数:
10

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值