一道阿里面试题

日前接到阿里一通面试电话。

有一题较为有趣,所以直接收录了下来。

需求:参照微信、支付宝红包,将金额拆分为相应人数的红包,且每个红包不得超过总金额的90%。(由于都是在电话里口述,不知道有没有听错需求,姑且就当它是正确的吧)

由于该需求会产生较多0.01的红包,但是暂且不论红包金额的算法,只论生成红包这段代码是否有错,望大神提点。

package com.demo;

import java.math.BigDecimal;
import java.util.Random;

public class Demo {

    /**
     * 单元测试
     */
    @org.junit.Test
    public void testSplitRedPacket() throws Exception {
        long startTime = System.currentTimeMillis();
        int sum = 0;
        BigDecimal amount;
        int pCount = 2;

        for (double i = 1; i < 10;) {
            sum = 0;
            amount = new BigDecimal(String.valueOf(i));
            int amountInt = amount.multiply(new BigDecimal("100")).intValue();

            int[] packets = splitRedPacket(amountInt, pCount);
            for (int packet : packets) {
                sum += packet;
            }
            BigDecimal bSum = new BigDecimal(Double.valueOf(sum / 100.0));

            assertCompare(bSum, amount);

            if(pCount < 20) {
                pCount++;
            } else {
                pCount = 2;
            }
            i = new BigDecimal(String.valueOf(i)).add(new BigDecimal("0.1")).doubleValue();
        }
        long endTime = System.currentTimeMillis();
        System.out.println("总消耗时间:" + (endTime - startTime) + "毫秒");
    }

    private void assertCompare(BigDecimal sum, BigDecimal amount) {
        // System.out.println(sum.doubleValue() + " " + amount.doubleValue());
        if(sum.doubleValue() != amount.doubleValue()) {
            throw new RuntimeException("拆分后总金额不相等,计算出错\nbd1=" + sum.doubleValue() + " bd2=" + amount.doubleValue());
        }
    }

    /**
     * 拆分红包
     * 
     * @param amount 总金额
     * @param pCount 人数
     * @return
     * @throws Exception
     */
    public int[] splitRedPacket(int amount, int pCount) throws Exception {

        // 总金额
        /*
         * TODO 总金额直接使用分计算
         */
        // 先将总金额单位改为分
        int amountInt = amount;

        // 验证最小红包金额
        verifyMinPacket(amountInt, pCount);

        int[] redPackets = new int[ pCount ];

        Random r = new Random(System.nanoTime());
        // 最大红包金额
        int max = amountInt;
        // 已发放总金额
        int sum = 0;
        // 每份的金额
        int part = 0;

        for (int i = 0; i < pCount - 1; i++) {
            // 预留金额
            int preAmount = preAmount(max, amountInt, pCount - i - 1);
            max -= preAmount;

            part = r.nextInt(max) + 1;

            // 余额
            max -= part;

            // 补偿预留金额
            max += preAmount;

            sum += part;
            // BigDecimal bPart = new BigDecimal(Double.valueOf(part / 100.0));
            redPackets[i] = part;

        }
        // 最后一份红包
        // redPackets[pCount - 1] = new BigDecimal(Double.valueOf((amountInt - sum) / 100.0));
        redPackets[pCount - 1] = amountInt - sum;
        return redPackets;
    }

    /**
     * 计算预留金额
     * 
     * @param balance 余额
     * @param amount 总金额
     * @param pCount 剩余人数
     * @return
     */
    private int preAmount(int balance, int amount, int pCount) {
        // 打9折
        int $9 = (int) (amount * 0.9);
        if(balance > $9) {
            // 余额必须大于总金额的90% 并且 10%足够剩余人数分
            int $1 = (int) (amount * 0.1);
            if($1 / pCount >= 1) {
                return $1;

            } else {
                // 10%不够分的时候
                return pCount;
            }
        }
        return pCount;
    }

    /**
     * 验证最小红包金额
     * 
     * @param amount 总金额
     * @param pCount 人数
     * @return
     * @throws Exception
     */
    private boolean verifyMinPacket(int amount, int pCount) throws Exception {
        if(amount / pCount >= 1) {
            return true;
        }
        throw new Exception("单个红包不能小于0.01");
    }

}

猜你喜欢

转载自tea-pig.iteye.com/blog/2354845