1169. Invalid Transactions**

​https://leetcode.com/problems/invalid-transactions/​

题目描述

A transaction is possibly invalid if:

  • the amount exceeds​​$1000​​, or;
  • if it occurs within (and including)​​60​​​ minutes of another transaction with the same name in a different city.
    Each transaction string​​​transactions[i]​​ consists of comma separated values representing the name, time (in minutes), amount, and city of the transaction.

Given a list of ​​transactions​​, return a list of transactions that are possibly invalid. You may return the answer in any order.

Example 1:

Input: transactions = ["alice,20,800,mtv","alice,50,100,beijing"]
Output: ["alice,20,800,mtv","alice,50,100,beijing"]
Explanation: The first transaction is invalid because the second transaction occurs within a difference of 60 minutes, have the same name and is in a different city. Similarly the second one is invalid too.

Example 2:

Input: transactions = ["alice,20,800,mtv","alice,50,1200,mtv"]
Output: ["alice,50,1200,mtv"]

Example 3:

Input: transactions = ["alice,20,800,mtv","bob,50,1200,mtv"]
Output: ["bob,50,1200,mtv"]

Constraints:

  • ​transactions.length <= 1000​
  • Each​​transactions[i]​​​ takes the form​​"{name},{time},{amount},{city}"​
  • Each​​{name}​​​ and​​{city}​​​ consist of lowercase English letters, and have lengths between​​1​​​ and​​10​​.
  • Each​​{time}​​​ consist of digits, and represent an integer between​​0​​​ and​​1000​​​.
    Each​​​{amount}​​​ consist of digits, and represent an integer between​​0​​​ and​​2000​​.

C++ 实现 1

此题差评, 描述不清, 另外我看题也不太认真, 浪费了大量时间. ????????????

读懂题意是关键. 这道题要求最后返回的是 invalid 的交易, 而交易被满足如下条件之一就被定义为 invalid:

  • 本次交易的​​amount > 1000​
  • 在本次交易 A 的股票名字和另一次交易 B 的股票名字相同的情况下, 交易发生的地点(city)不同并且交易时间在​​60​​ 分钟之内.

第二点限制条件可以理解为不能在短时间内跑到另一个城市对同一只股票发生交易.

然而, 要真正理解两个限制条件并写出代码, 我们有一些更深层的问题要问, 这可以从题目给出的示例出发. 第 1 个例子中, 由于不满足第二个条件, 所以两个交易都是 invalid 的. 第 2 个例子, 需要特别注意, 这个例子之所以返回 ​​["alice,50,1200,mtv"]​​​ 这个结果, 一方面我们考虑到第一个条件的限制, 而另一方面, 第二个条件也会对结果产生影响, 原因是输入的两个交易 ​​["alice,20,800,mtv","alice,50,1200,mtv"]​​​ 它们发生的交易地点都是 ​​"mtv"​​​, 在同一个城市, 所以即使时间上的差值小于 60, ​​"alice,20,800,mtv"​​​ 这个交易仍然是有效的. 假设这个示例的输入是 ​​["alice,20,800,omg","alice,50,1200,mtv"]​​, 此时返回什么 ? !
此时返回 ​​​["alice,20,800,omg","alice,50,1200,mtv"]​​​, 原因它们不满足第二个条件, (额外的 ​​"alice,50,1200,mtv"​​ 还不满足第一个条件).

下面代码的逻辑是:

  • ​parse_transaction​​​ 函数中, 使用​​record​​​ 保存每个访问过的 transaction,​​res​​ 保存 invalid 的 transaction
  • ​record​​​ 的结构比较复杂, 表示为​​record[name][city].push_back({time, amount})​​​, 第一个 map 的 key 是股票的 name, 而​​record[name]​​​ 中的 map 的 key 对应的是 city, 而​​record[name][city]​​​ 对应的 vector 保存的是​​{time, amount}​​ pair.
  • 对于当前访问的 transaction, 我们看​​name​​​ 是否已经存在于​​record​​​ 中. 不存在就放心的加入到​​record​​​ 中, 因为股票名字​​name​​ 不同, 不会影响 invalid transaction 的判断.
  • 如果​​record​​​ 已经存在了相同的​​name​​​, 也就是说, 针对​​name​​ 这只股票, 应该有交易发生了. 我们这时候就要判断它是否会违反第二个约束条件. 注意, 这里暂时不考虑第一个约束条件, 因为不管 amount 有没有超过 1000, 该交易都是要存储到 record 中!这一点需要切记.
  • 遍历​​name​​​ 这只股票发生交易的所有城市​​for (auto &city_record : record[name])​​,只有当城市不同的时候, 才需要进行时间上的比较.
  • 使用​​invalid​​​ 这个 bool 值来判断是否需要将本次交易设置为 invalid 的. 如果上一步的时间比较发现, 存在交易 B 和本次交易 A 发生的地点不同, 但是时间相差不超过 60, 那么不仅需要将交易 B 存入 invalid 交易集合​​res​​​ 中, 当比较完所有的交易后, 还要记得将本次交易 A 存入​​res​​ 中.
  • 之后, 如果​​invalid == true​​​ 或者本次交易的​​amount > 1000​​​, 那么就将本次交易加入​​res​​ 中.
  • 最后注意, 访问的每次交易都要存入​​record​​ 中!
class Solution {
private:
void parse_transaction(const string &transaction, unordered_map<string, unordered_map<string, vector<pair<int, int>>>> &record, unordered_set<string> &res) {
// 解析 transaction 字符串
stringstream ss(transaction);
string name, city;
int time, amount;
vector<string> tmp(4, "");
int i = 0;
while (getline(ss, tmp[i++], ','));
name = tmp[0], city = tmp.back();
time = std::stoi(tmp[1]), amount = std::stoi(tmp[2]);

bool invalid = false;
if (record.count(name)) { // 处理新 city
for (auto &city_record : record[name]) {
auto old_city = city_record.first;
auto pairs = city_record.second;
if (city != old_city) { // 只有 city 不相同时才需要比较时间
for (auto &q : pairs) {
auto tm = q.first;
auto money = q.second;
if (std::abs(tm - time) <= 60) {
invalid = true;
res.insert(name + "," + std::to_string(tm) +
"," + std::to_string(money) + "," +
old_city);
}
}
}
}
}
if (invalid || amount > 1000) res.insert(transaction);
record[name][city].push_back({time, amount});
}
public:
vector<string> invalidTransactions(vector<string>& transactions) {
unordered_map<string, unordered_map<string, vector<pair<int, int>>>> record;
unordered_set<string> tmp;
for (auto &t : transactions)
parse_transaction(t, record, tmp);
vector<string> res(tmp.begin(), tmp.end());
return res;
}
};