走楼梯的问题

问题:1000级台阶,一个人一步可以走2级也可以一步走1级,如果这个刚好把这1000级走完,那么有多少中走法?

思路如下:该问题就是N个红色球和M个黑色球的组合问题。假设一个黑色球代表1级台阶,一个红色球代表2级台阶,那么1000级台阶,就是M+2*N= 1000。然后根据

  
(n≥m)公式计算出结果即可。假设M>=N代入公式中的n = M+1,m=N。这里大家想想为什么是M+1,如果N>M,则代入公式中的n =N+1,m=M。这里卖个关子,为什么要加1?

下面给出三种解题的程序,分别是单线程处理、fork-join框架处理、threadpool处理,大家也看看具体的性能

1、单线程

package louti;

import java.math.BigInteger;
import java.util.LinkedList;
import java.util.List;

public class LouTiWenTi {

	public static final int MAX_NUM = 3000;// 楼梯总的台阶数
	public static final int MAX_2_SETP_NUM = MAX_NUM / 2;// 一步走两级台阶,最大的步数
	public static final int MAX_1_STEP_NUM = MAX_NUM;// 一步走一级台阶,最大的步数

	public static void main(String ... args) {
		System.out.println(MAX_NUM + "级台阶,一个人一步可以走2级台阶也可以一步走1级台阶,如果这个人刚好把这" + MAX_NUM + "级台阶走完,总共有多少种走法?步骤如下:");
		long begin = System.currentTimeMillis();
		BigInteger cnt = new BigInteger("0");
		for (int step1, step2 = 0; step2 <= MAX_2_SETP_NUM; step2++) {
			step1 = MAX_NUM - 2 * step2;
			if (step1 >= step2) {
				BigInteger sum = compute(step1 + 1, step2);
				System.out.println("走" + step1 + "个一级台阶," + step2 + "个二级台阶.有" + sum + "种走法");
				cnt = cnt.add(sum);
			} else if (step2 > step1) {
				BigInteger sum = compute(step2 + 1, step1);;
				System.out.println("走" + step1 + "个一级台阶," + step2 + "个二级台阶.有" + sum + "种走法");
				cnt = cnt.add(sum);
			}
		}
		System.out.println("总共有" + cnt + "种走法.耗费"+(System.currentTimeMillis()-begin)+"毫秒");
	}

	public static BigInteger compute(int m, int n) {
		if (m < n) {
			throw new RuntimeException("入参m必须大于等于n");
		}
		if (n == 0) {
			return new BigInteger("1");
		}
		int m_n = m - n;
		List<Integer> mList = new LinkedList<Integer>();
		List<Integer> nList = new LinkedList<Integer>();
		List<Integer> m_nList = new LinkedList<Integer>();

		if (m_n >= n) {
			for (int i = m; i > m_n; i--) {
				mList.add(i);
			}
			for (int i = 1; i <= n; i++) {
				nList.add(i);
			}
		} else {
			for (int i = m; i > n; i--) {
				mList.add(i);
			}
			for (int i = 1; i <= (m - n); i++) {
				m_nList.add(i);
			}

		}
		// 做约分
		if (nList.size() > 0) {
			for (int i = 0; i < mList.size(); i++) {
				for (int j = 0; j < nList.size(); j++) {
					if (Integer.parseInt(String.valueOf(mList.get(i))) == Integer.parseInt(String.valueOf(nList.get(j)))) {
						mList.remove(i);
						nList.remove(j);
						i--;
						break;
					}
				}
			}
		}
		// 做约分
		if (m_nList.size() > 0) {
			for (int i = 0; i < mList.size(); i++) {
				for (int j = 0; j < m_nList.size(); j++) {
					if (Integer.parseInt(String.valueOf(mList.get(i))) == Integer.parseInt(String.valueOf(m_nList.get(j)))) {
						mList.remove(i);
						m_nList.remove(j);
						i--;
						break;
					}
				}
			}
		}
		// 做约分
		if (nList.size() > 0) {
			for (int i = 0; i < mList.size(); i++) {
				for (int j = 0; j < nList.size(); j++) {
					int a = mList.get(i);
					int b = nList.get(j);
					int gys = gongyue(a, b);
					if (gys > 1) {
						nList.set(j, b / gys);
						mList.set(i, a / gys);
					}
				}
			}
		}
		// 做约分
		if (m_nList.size() > 0) {
			for (int i = 0; i < mList.size(); i++) {
				for (int j = 0; j < m_nList.size(); j++) {
					int a = mList.get(i);
					int b = m_nList.get(j);
					int gys = gongyue(a, b);
					if (gys > 1) {
						m_nList.set(j, b / gys);
						mList.set(i, a / gys);
					}
				}
			}
		}

		// 阶乘分子
		BigInteger fenzi = new BigInteger("1");
		for (int i = 0; i < mList.size(); i++) {
			fenzi = fenzi.multiply(new BigInteger(String.valueOf(mList.get(i))));
		}
		// 阶乘分母1
		BigInteger fenmu1 = new BigInteger("1");
		for (int i = 0; i < nList.size(); i++) {
			fenmu1 = fenmu1.multiply(new BigInteger(String.valueOf(nList.get(i))));
		}
		// 阶乘分母2
		BigInteger fenmu2 = new BigInteger("1");
		for (int i = 0; i < m_nList.size(); i++) {
			fenmu2 = fenmu2.multiply(new BigInteger(String.valueOf(m_nList.get(i))));
		}

		return fenzi.divide(fenmu1.multiply(fenmu2));
	}

	// 求最小公倍数
	public static int gongbei(int a, int b) {
		return (a * b) / gongyue(a, b);
	}

	// 求最大公约数函数
	public static int gongyue(int a, int b) {
		int gongyue = 0;
		if (a < b) { // 交换a、b的值
			a = a + b;
			b = a - b;
			a = a - b;
		}
		if (a % b == 0) {
			gongyue = b;
		}
		while (a % b > 0) {
			a = a % b;
			if (a < b) {
				a = a + b;
				b = a - b;
				a = a - b;
			}
			if (a % b == 0) {
				gongyue = b;
			}
		}
		return gongyue;
	}

}
2、fork-join

package louti;

import java.math.BigInteger;
import java.util.LinkedList;
import java.util.List;
import java.util.concurrent.ForkJoinPool;
import java.util.concurrent.Future;
import java.util.concurrent.RecursiveTask;

public class LouTiWenTiFockJoin extends RecursiveTask<BigInteger> {

	/**
	 * 
	 */
	private static final long serialVersionUID = 1L;

	public static final int MAX_NUM = 3000;// 楼梯总的台阶数
	public static final int MAX_2_SETP_NUM = MAX_NUM / 2;// 一步走两级台阶,最大的步数
	public static final int MAX_1_STEP_NUM = MAX_NUM;// 一步走一级台阶,最大的步数
	public static final int MAX_TASK_NUM = 10;
	public String[] taskArray;
	public int start;
	public int end;

	public LouTiWenTiFockJoin(String[] taskArray, int start, int end) {
		this.taskArray = taskArray;
		this.start = start;
		this.end = end;
	}

	@Override
	protected BigInteger compute() {
		BigInteger cnt = new BigInteger("0");
		if (end - start < MAX_TASK_NUM) {
			for (int i = start; i < end; i++) {
				String[] mnStrArr = taskArray[i].split(",");
				int m = Integer.parseInt(mnStrArr[0]);
				int n = Integer.parseInt(mnStrArr[1]);
				BigInteger result = new BigInteger("0");
				if (m >= n) {
					result = compute(m + 1, n);
					System.out.println("走" + m + "个一级台阶," + n + "个二级台阶.有" + result + "种走法");
					cnt = cnt.add(result);
				} else if (m < n) {
					result = compute(n + 1, m);
					System.out.println("走" + m + "个一级台阶," + n + "个二级台阶.有" + result + "种走法");
					cnt = cnt.add(result);
				}
				cnt.add(result);
			}
			return cnt;
		} else {
			int middle = (start + end) / 2;
			LouTiWenTiFockJoin left = new LouTiWenTiFockJoin(taskArray, start, middle);
			LouTiWenTiFockJoin right = new LouTiWenTiFockJoin(taskArray, middle, end);
			left.fork();
			right.fork();
			return left.join().add(right.join());
		}

	}

	public static BigInteger compute(int m, int n) {
		if (m < n) {
			throw new RuntimeException("入参m必须大于等于n");
		}
		if (n == 0) {
			return new BigInteger("1");
		}
		int m_n = m - n;
		List<Integer> mList = new LinkedList<Integer>();
		List<Integer> nList = new LinkedList<Integer>();
		List<Integer> m_nList = new LinkedList<Integer>();

		if (m_n >= n) {
			for (int i = m; i > m_n; i--) {
				mList.add(i);
			}
			for (int i = 1; i <= n; i++) {
				nList.add(i);
			}
		} else {
			for (int i = m; i > n; i--) {
				mList.add(i);
			}
			for (int i = 1; i <= (m - n); i++) {
				m_nList.add(i);
			}

		}
		// 做约分
		if (nList.size() > 0) {
			for (int i = 0; i < mList.size(); i++) {
				for (int j = 0; j < nList.size(); j++) {
					if (Integer.parseInt(String.valueOf(mList.get(i))) == Integer.parseInt(String.valueOf(nList.get(j)))) {
						mList.remove(i);
						nList.remove(j);
						i--;
						break;
					}
				}
			}
		}
		// 做约分
		if (m_nList.size() > 0) {
			for (int i = 0; i < mList.size(); i++) {
				for (int j = 0; j < m_nList.size(); j++) {
					if (Integer.parseInt(String.valueOf(mList.get(i))) == Integer.parseInt(String.valueOf(m_nList.get(j)))) {
						mList.remove(i);
						m_nList.remove(j);
						i--;
						break;
					}
				}
			}
		}
		// 做约分
		if (nList.size() > 0) {
			for (int i = 0; i < mList.size(); i++) {
				for (int j = 0; j < nList.size(); j++) {
					int a = mList.get(i);
					int b = nList.get(j);
					int gys = gongyue(a, b);
					if (gys > 1) {
						nList.set(j, b / gys);
						mList.set(i, a / gys);
					}
				}
			}
		}
		// 做约分
		if (m_nList.size() > 0) {
			for (int i = 0; i < mList.size(); i++) {
				for (int j = 0; j < m_nList.size(); j++) {
					int a = mList.get(i);
					int b = m_nList.get(j);
					int gys = gongyue(a, b);
					if (gys > 1) {
						m_nList.set(j, b / gys);
						mList.set(i, a / gys);
					}
				}
			}
		}

		// 阶乘分子
		BigInteger fenzi = new BigInteger("1");
		for (int i = 0; i < mList.size(); i++) {
			fenzi = fenzi.multiply(new BigInteger(String.valueOf(mList.get(i))));
		}
		// 阶乘分母1
		BigInteger fenmu1 = new BigInteger("1");
		for (int i = 0; i < nList.size(); i++) {
			fenmu1 = fenmu1.multiply(new BigInteger(String.valueOf(nList.get(i))));
		}
		// 阶乘分母2
		BigInteger fenmu2 = new BigInteger("1");
		for (int i = 0; i < m_nList.size(); i++) {
			fenmu2 = fenmu2.multiply(new BigInteger(String.valueOf(m_nList.get(i))));
		}

		return fenzi.divide(fenmu1.multiply(fenmu2));
	}

	// 求最小公倍数
	public static int gongbei(int a, int b) {
		return (a * b) / gongyue(a, b);
	}

	// 求最大公约数函数
	public static int gongyue(int a, int b) {
		int gongyue = 0;
		if (a < b) { // 交换a、b的值
			a = a + b;
			b = a - b;
			a = a - b;
		}
		if (a % b == 0) {
			gongyue = b;
		}
		while (a % b > 0) {
			a = a % b;
			if (a < b) {
				a = a + b;
				b = a - b;
				a = a - b;
			}
			if (a % b == 0) {
				gongyue = b;
			}
		}
		return gongyue;
	}

	public static void main(String ... args) throws Exception {
		System.out.println(MAX_NUM + "级台阶,一个人一步可以走2级台阶也可以一步走1级台阶,如果这个人刚好把这" + MAX_NUM + "级台阶走完,总共有多少种走法?步骤如下:");
		long begin = System.currentTimeMillis();
		String[] taskArr = new String[MAX_2_SETP_NUM + 1];
		for (int step1, step2 = 0; step2 <= MAX_2_SETP_NUM; step2++) {
			step1 = MAX_NUM - 2 * step2;
			taskArr[step2] = step1 + "," + step2;
		}

		// 创建包含Runtime.getRuntime().availableProcessors()返回值作为个数的并行线程的ForkJoinPool
		ForkJoinPool forkJoinPool = new ForkJoinPool();
		// 提交可分解的PrintTask任务
		LouTiWenTiFockJoin task = new LouTiWenTiFockJoin(taskArr, 0, taskArr.length);
		Future<BigInteger> future = forkJoinPool.submit(task);
		while (!task.isDone()) {

		}
		System.out.println("总共有" + future.get() + "种走法.耗费" + (System.currentTimeMillis() - begin) + "毫秒");
		// 关闭线程池
		forkJoinPool.shutdown();
	}
}

3、threadpool

package louti;

import java.math.BigInteger;
import java.util.LinkedList;
import java.util.List;
import java.util.concurrent.Callable;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;

public class LouTiWenTiThreadPool {

	public static final int MAX_NUM = 2000;// 楼梯总的台阶数
	public static final int MAX_2_SETP_NUM = MAX_NUM / 2;// 一步走两级台阶,最大的步数
	public static final int MAX_1_STEP_NUM = MAX_NUM;// 一步走一级台阶,最大的步数

	public static void main(String ... args) throws Exception {
		System.out.println(MAX_NUM + "级台阶,一个人一步可以走2级台阶也可以一步走1级台阶,如果这个人刚好把这" + MAX_NUM + "级台阶走完,总共有多少种走法?步骤如下:");
		long begin = System.currentTimeMillis();
		ExecutorService executor = Executors.newCachedThreadPool(Executors.defaultThreadFactory());
		Future<BigInteger>[] futures = new Future[MAX_2_SETP_NUM + 1];
		final CountDownLatch latch = new CountDownLatch(MAX_2_SETP_NUM + 1);

		for (int step2 = 0; step2 <= MAX_2_SETP_NUM; step2++) {
			int step1 = MAX_NUM - 2 * step2;
			futures[step2] = (Future<BigInteger>)executor.submit(new Task(step1, step2, latch));
		}
		executor.shutdown();
		latch.await();
		BigInteger cnt = new BigInteger("0");
		for (int i = 0; i < futures.length; i++) {
			cnt = cnt.add(futures[i].get());
		}
		System.out.println("总共有" + cnt + "种走法.耗费" + (System.currentTimeMillis() - begin) + "毫秒");
		
	}

	static class Task implements Callable<BigInteger> {

		private int m;
		private int n;
		private CountDownLatch latch;

		public Task(int m, int n, CountDownLatch latch) {
			this.m = m;
			this.n = n;
			this.latch = latch;
		}

		@Override
		public BigInteger call() throws Exception {
			BigInteger result = new BigInteger("0");
			if (m >= n) {
				result = compute(m + 1, n);
				System.out.println("走" + m + "个一级台阶," + n + "个二级台阶.有" + result + "种走法");
			} else if (m < n) {
				result = compute(n + 1, m);
				System.out.println("走" + m + "个一级台阶," + n + "个二级台阶.有" + result + "种走法");
			}
			this.latch.countDown();
			return result;
		}

		public static BigInteger compute(int m, int n) {
			if (m < n) {
				throw new RuntimeException("入参m必须大于等于n");
			}
			if (n == 0) {
				return new BigInteger("1");
			}
			int m_n = m - n;
			List<Integer> mList = new LinkedList<Integer>();
			List<Integer> nList = new LinkedList<Integer>();
			List<Integer> m_nList = new LinkedList<Integer>();

			if (m_n >= n) {
				for (int i = m; i > m_n; i--) {
					mList.add(i);
				}
				for (int i = 1; i <= n; i++) {
					nList.add(i);
				}
			} else {
				for (int i = m; i > n; i--) {
					mList.add(i);
				}
				for (int i = 1; i <= (m - n); i++) {
					m_nList.add(i);
				}

			}
			// 做约分
			if (nList.size() > 0) {
				for (int i = 0; i < mList.size(); i++) {
					for (int j = 0; j < nList.size(); j++) {
						if (Integer.parseInt(String.valueOf(mList.get(i))) == Integer.parseInt(String.valueOf(nList.get(j)))) {
							mList.remove(i);
							nList.remove(j);
							i--;
							break;
						}
					}
				}
			}
			// 做约分
			if (m_nList.size() > 0) {
				for (int i = 0; i < mList.size(); i++) {
					for (int j = 0; j < m_nList.size(); j++) {
						if (Integer.parseInt(String.valueOf(mList.get(i))) == Integer.parseInt(String.valueOf(m_nList.get(j)))) {
							mList.remove(i);
							m_nList.remove(j);
							i--;
							break;
						}
					}
				}
			}
			// 做约分
			if (nList.size() > 0) {
				for (int i = 0; i < mList.size(); i++) {
					for (int j = 0; j < nList.size(); j++) {
						int a = mList.get(i);
						int b = nList.get(j);
						int gys = gongyue(a, b);
						if (gys > 1) {
							nList.set(j, b / gys);
							mList.set(i, a / gys);
						}
					}
				}
			}
			// 做约分
			if (m_nList.size() > 0) {
				for (int i = 0; i < mList.size(); i++) {
					for (int j = 0; j < m_nList.size(); j++) {
						int a = mList.get(i);
						int b = m_nList.get(j);
						int gys = gongyue(a, b);
						if (gys > 1) {
							m_nList.set(j, b / gys);
							mList.set(i, a / gys);
						}
					}
				}
			}

			// 阶乘分子
			BigInteger fenzi = new BigInteger("1");
			for (int i = 0; i < mList.size(); i++) {
				fenzi = fenzi.multiply(new BigInteger(String.valueOf(mList.get(i))));
			}
			// 阶乘分母1
			BigInteger fenmu1 = new BigInteger("1");
			for (int i = 0; i < nList.size(); i++) {
				fenmu1 = fenmu1.multiply(new BigInteger(String.valueOf(nList.get(i))));
			}
			// 阶乘分母2
			BigInteger fenmu2 = new BigInteger("1");
			for (int i = 0; i < m_nList.size(); i++) {
				fenmu2 = fenmu2.multiply(new BigInteger(String.valueOf(m_nList.get(i))));
			}

			return fenzi.divide(fenmu1.multiply(fenmu2));
		}

		// 求最小公倍数
		public static int gongbei(int a, int b) {
			return (a * b) / gongyue(a, b);
		}

		// 求最大公约数函数
		public static int gongyue(int a, int b) {
			int gongyue = 0;
			if (a < b) { // 交换a、b的值
				a = a + b;
				b = a - b;
				a = a - b;
			}
			if (a % b == 0) {
				gongyue = b;
			}
			while (a % b > 0) {
				a = a % b;
				if (a < b) {
					a = a + b;
					b = a - b;
					a = a - b;
				}
				if (a % b == 0) {
					gongyue = b;
				}
			}
			return gongyue;
		}

	}

}

以下是台阶数目为1000、2000、3000在同一机器环境下的性能对比。单位(毫秒)

 100020003000
单线程274034808168578
forkjoin17591318061389
threadpool16511327711120


评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值