【Java | LeetCode 1169. 查询无效交易】题解 & 思考

1169.查询无效交易 题解 & 思考

一、题目

1169.查询无效交易

如果出现下述两种情况,交易可能无效:
① 交易金额超过 ¥1000
② 它和另一个城市中同名的另一笔交易相隔不超过 60 分钟(包含 60 分钟整)
每个交易字符串 transactions[i] 由一些用逗号分隔的值组成,这些值分别表示交易的名称,时间(以分钟计),金额以及城市。
给你一份交易清单 transactions,返回可能无效的交易列表。你可以按任何顺序返回答案。
提示
[来源:https://leetcode-cn.com/problems/invalid-transactions/]

二、初次题解

我们的思路:先存储,后过滤
这种题解使用 HashMap 作为存储容器,且将交易人员作为Key将交易清单划分至Value,实现了账单写至账户名下。每次取出需调用forEach方法,排序实现了Comparator接口,使得整个题解过于冗余。

虽作为题解有些许笨重,但这样的存储方式方便了后续操作。不过这不是解本题的重点,所以实际上只需将每笔交易用两次循环依次比较即可。

class Solution {
    public List<String> invalidTransactions(String[] transactions) {
    	//记录数组长度
        int len = transactions.length;
        //构建结果List集合
        List<String> result = new ArrayList<>(len);
        //构建Map键值对,以人为单位存储数据,追求数据对应性
        Map<String,List<Transaction>> map = new HashMap<>();
	
		/*
		 * 第一步:先存储
		 */
		//循环将字符串分割、构成“清单Transaction”对象,在逐次放入Map结构中
        for (int i = 0; i < len; i++) {
            String[] s = transactions[i].split(",");	//分割字符串
            if(!map.containsKey(s[0])){					//当map中不存在Key,就将Key值放入Map中
                List<Transaction> list = new ArrayList<>(len);
                map.put(s[0],list);
            }
            Transaction t = new Transaction(		//创建相应的Transaction对象
         		s[0],
	            Integer.valueOf(s[1]),
	            Integer.valueOf(s[2]),
	            s[3]
            );	
            map.get(s[0]).add(t);		//获取Key值并放入“清单Transaction”对象
        }
		
		/*
		 * 第二步:后存储
		 */
		//将Map中的值通过forEach方法依次取出、排序再将符合条件的结果放入结果List中
        map.forEach((s,ts) -> {
            ts.sort(new Comparator<Transaction>() {	//重写 Comparator 接口排序
                @Override
                public int compare(Transaction o1, Transaction o2) {
                    return o1.time - o2.time;
                }
            });
            if(ts.size() > 1){						//交易人员有多笔交易
                int size = ts.size();
                int[] inner = new int[size];		//若交易有效,则“亮灯”(即对应位数字+1)
                for (int i = 0; i < size; i++) {
                    Transaction t1 = ts.get(i);
                    for (int j = i + 1; j < size ; j++) {
                        Transaction t2 = ts.get(j);
                        if((!t2.city.equals(t1.city) && t2.time - t1.time <= 60)){
                            inner[i]++;
                            inner[j]++;
                        }
                    }
                    if(t1.cost >= 1000){
                        inner[i]++;
                    }
                }
                for (int i = 0; i < size; i++) {		//根据指示取出值并加入List集合
                    if(inner[i] > 0){
                        result.add(ts.get(i).toString());
                    }
                }
            }else{									//交易人员仅有单笔交易
                Transaction single = ts.get(0);
                if(single.cost >= 1000){
                    result.add(single.toString());
                }
            }
            
        });
        //返回结果List
        return result;
    }
    /**
     * 创建交易清单类,用以存储相关数据
     */
    class Transaction{
        public String name;
        public int time;
        public int cost;
        public String city;

        public Transaction(String name, int time, int cost, String city) {
            this.name = name;
            this.time = time;
            this.cost = cost;
            this.city = city;
        }
		
		//重写toString方法,方便加入List集合
        @Override
        public String toString() {
            return  name + "," + time + "," + cost + "," + city;
        }
    }
}

初次题解

三、优化题解

我们的思路不变,仍是:先存储,后过滤
这种题解将所有的对象存储至数组中,减轻了存储压力、加快了运行速度,不用构建HashMap容器,简单的使用两层循环加判断解决了相应问题,作为优化方案相当合适。

class Solution {
    public List<String> invalidTransactions(String[] transactions) {
    	//记录数组长度
        int len = transactions.length;
        //维护对象数组,长度与原数组相等
        Transactions[] arr = new Transactions[len];
		/*
		 * 第一步:先存储
		 */
		//循环
        for (int i = 0; i < len; i++) {
        	//分割字符串
            String[] tmp = transactions[i].split(",");
            //创建相应的Transaction对象,并放入“清单Transactions”对象数组中
            arr[i] = new Transactions(
                tmp[0], 
                Integer.valueOf(tmp[1]), 
                Integer.valueOf(tmp[2]), 
                tmp[3]
            );
        }
		//构建结果List集合
        List<String> result= new ArrayList<>();
		/*
		 * 第二步:后过滤
		 */
		//循环开始比较
        for (int i = 0; i <len; i++) {
        	//先判断第一个条件
            if (arr[i].money > 1000) {
                result.add(transactions[i]);
                continue;
            }
			//再循环判断该交易与其他交是否满足第二个条件
            for(int j = 0; j < len; j++) {
            	//如若相同交易则不进行比较
                if (i == j) continue;
				//
                if (arr[i].name.equals(arr[j].name) && !arr[i].city.equals(arr[j].city) &&
                    Math.abs(arr[i].time - arr[j].time) <= 60) {
                    result.add(transactions[i]);
                    break;
                }
            }
        }

        return result;
    }
}

class Transactions {
    String name;
    Integer time;
    Integer money;
    String city;

    public Transactions(String name, Integer time, Integer money, String city) {
        this.name = name;
        this.time = time;
        this.money = money;
        this.city = city;
    }
}

优化题解
【思考】

  • 可以看到这种方案的运行用时降低了许多。在解决问题的过程中,我们应灵活使用数组、容器,在众多结构中,Java的容器提供了很多好的方法、接口供我们使用,但数组是最基础的结构,也是常用结构之一,在某些情况下可以简化操作。我们应结合情景慎重考虑,选择合适的结构存储数据,从而减少不必要的开销。
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值