`
tang9140
  • 浏览: 35072 次
  • 性别: Icon_minigender_1
  • 来自: 深圳
社区版块
存档分类
最新评论

平安科技在线编程大赛:一份“奇妙”的银行流水[分享]

 
阅读更多
题目详情

一份银行流水数据,因打印模糊导致部分金额不清楚。

收入、支出、余额满足以下3条规则:

1、收入、支出、余额三列都是数字

2、同一行收入和支出的值不能同时为非零值

3、第N-1行余额(+第N行收入或-第N行支出)=第N行余额

程序语言: java

请按照规则编写算法,修复不清楚的值


输入描述:

输入数据最多25行,每行都包含四个数据,分别是:数据编号,收入、支出、余额,模糊的数据以?表示,

它们之间以;隔开。

以文件结尾。第一组数据为初始数据值,收入、支出、余额数据保留2位小数

输出描述:

以输入的数据顺序输出修复后的数据。


答题说明

输入样例:

流水记录ID;收入;支出;余额

1;0.00;51.90;1945.45

2;0.00;1000.00;?

输出样例:

流水记录ID;收入;支出;余额

1;0.00;51.90;1945.45

2;0.00;1000.00;945.45


试了30次,无法通过。求大神指点。不多说,代码如下

import java.io.IOException;
import java.math.BigDecimal;
import java.util.Scanner;

public class Main {
    
    /**
     * 标志:代表?,即未知数
     */
    private static BigDecimal Flag = new BigDecimal(-1);
    
    /**
     * 代表0
     */
    private static BigDecimal ZERO = new BigDecimal(0);
    
    /**
     * 输入数据最大行数
     */
    private static int MaxLine = 25;
    
    /**
     * <解析为BigDecimal>
     * @param input
     * @return
     */
    private static BigDecimal parse(String input) {
        if (input.equals("?")) {
            return Flag;
        }
        else if (input.equals("0.00") || input.equals("0")) {
            return ZERO;
        }
        return new BigDecimal(input);
    }
    
    /**
     * <处理单行信息>
     * @param line
     * @return
     */
    private static BigDecimal[] parseLine(String line) {
        String[] strs = line.split(";");
        if( strs.length != 4){
            return null;
        }
        
        BigDecimal[] out = null;
        try{
            BigDecimal income = parse(strs[1]);
            BigDecimal payout = parse(strs[2]);
            BigDecimal balance = parse(strs[3]);
            
            if (income != Flag && income != ZERO && payout == Flag)
                payout = ZERO;
            else if (payout != Flag && payout != ZERO && income == Flag)
                income = ZERO;
            
            out = new BigDecimal[]
            {income, payout, balance};
        }catch(Exception e){
            return null;
        }
        return out;
    }
    
    /**
     * <格式化输出>
     * @param f
     * @return
     */
    public static String show(BigDecimal f) {
        if (f == Flag) {
            return "?";
        }
        else if (f == ZERO) {
            return "0.00";
        }
        else {
            return f.setScale(2, BigDecimal.ROUND_HALF_UP).toString();
        }
    }
    
    /**
     * <处理当前行及上一行余额已知,且当前行中存在2个未知数情形>
     * @param datas
     * @param currentLineBalanceIndex
     */
    private static void doCaseOne(BigDecimal[] datas, int currentLineBalanceIndex) {
        BigDecimal diff = datas[currentLineBalanceIndex].subtract(datas[currentLineBalanceIndex - 3]);
        if (diff.signum() == -1) {
            datas[currentLineBalanceIndex - 1] = diff.negate();
            datas[currentLineBalanceIndex - 2] = ZERO;
        }
        else {
            datas[currentLineBalanceIndex - 2] = diff;
            datas[currentLineBalanceIndex - 1] = ZERO;
        }
    }
    
    public static void main(String[] args) throws IOException {
        Scanner cin = new Scanner(System.in);
        
        String lineStr = null;
        BigDecimal[] datas = new BigDecimal[MaxLine * 3 + 1];//存放收入,支出,余额数据,从下标为1开始存
        String[] idStrs = new String[MaxLine + 1];//存放每行编号信息,从下标为1开始存
        int[] lineMisCount = new int[MaxLine + 1];//存放每行未知数总数,从下标为1开始存,可为0-3之间的值
        int lineCount = 1;//已读取行数统计
        int dataCount = 1;//已读取数据统计
        int misCount = 0;//未知数统计
        String firstLineStr = null;
        
        while (cin.hasNext() && lineCount < MaxLine + 1) {
            if (firstLineStr == null) {//表头
                firstLineStr = cin.nextLine();
                continue;
            }
            lineStr = cin.nextLine();
            BigDecimal[] d = parseLine(lineStr);
            if(d == null){
                continue; 
            }
            idStrs[lineCount] = lineStr.substring(0, lineStr.indexOf(";"));
            
            int lineMis = 0;
            for (BigDecimal t : d) {
                if (t == Flag) {
                    misCount++;
                    lineMis++;
                }
            }
            lineMisCount[lineCount] = lineMis;
            datas[dataCount++] = d[0];
            datas[dataCount++] = d[1];
            datas[dataCount++] = d[2];
            
            if (lineCount >= 2 && misCount > 0) {//从第二行起,每读一行,循环去倒推当前行及上一行中的未知数
                for (int i = lineCount; i > 1 && misCount > 0; i--) {
                    
                    //==========断层情况开始============
                    if (lineMisCount[i] == 3) {//当前行中三个数未知,将无法倒推出前面所有行中的数据,直接跳出循环,断层原理
                        break;
                    }
                    int index = i * 3;//当前行对应的余额下标
                    if (lineMisCount[i - 1] == 0) {//上一行数据全部已知,则最多只能推出本行的未知数据,断层原理
                        if (lineMisCount[i] == 1) {
                            if (datas[index] == Flag) {//形如 100.00  0.00 ? 形式
                                datas[index] = datas[index - 3].add(datas[index - 2].subtract(datas[index - 1]));
                            }
                            else {//形如  ? 0.00 100.00 或 0.00 ? 100.00形式
                                BigDecimal diff = datas[index].subtract(datas[index - 3]);
                                if (diff.signum() == -1)
                                    datas[index - 1] = diff.negate();
                                else
                                    datas[index - 2] = diff;
                            }
                            lineMisCount[i]--;
                            misCount--;
                        }
                        else if (lineMisCount[i] == 2) {
                            if (datas[index] != Flag) {//形如 ? ? 100.00形式
                                doCaseOne(datas, index);
                                lineMisCount[i] = 0;
                                misCount -= 2;
                            }
                        }//其它 80.00 0.00 100.00 及 ? ? ? 这两种情况不考虑,前一种没有未知数据,后一种情况,根据之前的判断,不可能出现
                        break;
                    }
                    //==========断层情况结束============
                    
                    if (lineMisCount[i] == 0) {//当前行数据全部已知
                        if (datas[index - 3] == Flag) {//推出上一行中的余额
                            datas[index - 3] = datas[index].add(datas[index - 1]).subtract(datas[index - 2]);
                            lineMisCount[i - 1]--;
                            misCount--;
                        }
                        continue;
                    }
                    if (lineMisCount[i] == 2) {//当前行两个未知数
                        if (datas[index] != Flag && datas[index - 3] != Flag) {//形如 ? ? 100.00形式 及上一行的  x x 100.00形式
                            doCaseOne(datas, index);
                            lineMisCount[i] = 0;
                            misCount -= 2;
                        }//其它情况既无法推出本行未知数,也无法推出上一行的未知数
                        continue;
                    }
                    
                    if (lineMisCount[i] == 1) {//当前行一个未知数
                        if (datas[index - 3] != Flag) {//只有上一行余额已知时才能推导出本行未知数
                            if (datas[index - 1] == Flag) {
                                datas[index - 1] = datas[index - 3].subtract(datas[index]);
                            }
                            else if (datas[index - 2] == Flag) {
                                datas[index - 2] = datas[index].subtract(datas[index - 3]);
                            }
                            else {
                                datas[index] = datas[index - 3].add(datas[index - 2]).subtract(datas[index - 1]);
                            }
                            lineMisCount[i] = 0;
                            misCount--;
                        }
                    }
                    
                }
            }
            lineCount++;
        }
        lineCount--;
        
        int size = lineCount * 3;
        if (firstLineStr != null) {
            System.out.println(firstLineStr);//输出表头
        }
        for (int i = 1; i <= size; i += 3) {
            int lineNum = i / 3 + 1;
            System.out.println(idStrs[lineNum] + ";" + show(datas[i]) + ";" + show(datas[i + 1]) + ";"
                + show(datas[i + 2]));
        }
        cin.close();
    }
}

上面用的是BigDecimal来存放数据,个人觉得用double存也是可以的。

版权声明:本文为博主原创文章,未经博主允许不得转载。

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics