Merchant Fraud Thresholds and Disputes
Problem statement
Process merchant charges and disputes, then return the merchant IDs that are fraudulent after every event has been processed. Each merchant belongs to a merchant category code (MCC), and each MCC has its own fraud threshold.
Inputs
- Each row of
mccThresholdsis[mcc, threshold]. - Each row of
merchantsis[merchantId, mcc]. fraudulentCodesandnonFraudulentCodesare disjoint code lists. Every charge code belongs to exactly one list.- A charge event is
["CHARGE", transactionId, merchantId, code]. A dispute event is["DISPUTE", transactionId].
Charge and dispute rules
- A new transaction ID records one charge and increments that merchant's total charge count. Increment its fraud count only if the charge code is in
fraudulentCodes. - A repeated
CHARGEuses the same merchant and code as the original and has no effect. - Every
DISPUTErefers to an earlier charge. The first dispute removes that charge from the merchant's fraud count if it was fraudulent. It does not remove the charge from the total count: the transaction still occurred. - A dispute of a non-fraudulent charge and every repeated dispute have no effect. A repeated charge cannot restore disputed fraud.
Threshold rules
- A threshold without a decimal point, such as
2, is an integer fraud-count threshold. The merchant is fraudulent when its remaining fraud count is at least that value. - A threshold with a decimal point, such as
0.5or1.0, is a fraud-ratio threshold. The merchant is fraudulent whenremaining fraud count / total charge countis at least that exact decimal value. - A merchant with no charges is not fraudulent. Reevaluate thresholds using the final counts; a merchant may stop being fraudulent after a dispute or an additional non-fraudulent charge.
Return every fraudulent merchant ID exactly once, sorted in ascending lexicographic order. The threshold comparison, duplicate handling, preceding-charge requirement, dispute denominator, and final-state output are the practice rules for this exercise.
Function
fraudulentMerchants(mccThresholds: String[][], merchants: String[][], fraudulentCodes: String[], nonFraudulentCodes: String[], events: String[][]) → String[]Examples
Example 1
mccThresholds = [["retail","2"],["grocery","0.5"]]merchants = [["A","retail"],["B","grocery"]]fraudulentCodes = ["F"]nonFraudulentCodes = ["N"]events = [["CHARGE","a1","A","F"],["CHARGE","a2","A","F"],["CHARGE","b1","B","F"],["CHARGE","b2","B","N"],["DISPUTE","a1"]]return = ["B"]A has one remaining fraudulent charge, below its count threshold of 2. B has one fraudulent charge out of two total charges, exactly its ratio threshold of 0.5.
Example 2
mccThresholds = [["count","1"],["ratio","1.0"]]merchants = [["countShop","count"],["ratioShop","ratio"]]fraudulentCodes = ["F"]nonFraudulentCodes = ["N"]events = [["CHARGE","c1","countShop","F"],["CHARGE","c2","countShop","N"],["CHARGE","r1","ratioShop","F"],["CHARGE","r2","ratioShop","N"]]return = ["countShop"]The integer threshold requires one fraudulent charge, so countShop qualifies. The decimal threshold requires a fraud ratio of 1.0; ratioShop has only 1/2.
Example 3
mccThresholds = [["mcc","1"]]merchants = [["store","mcc"]]fraudulentCodes = ["F"]nonFraudulentCodes = ["N"]events = [["CHARGE","t1","store","F"],["DISPUTE","t1"],["DISPUTE","t1"],["CHARGE","t1","store","F"]]return = []The first dispute reverses the one fraudulent charge. A repeated dispute cannot decrease the count again, and a repeated charge cannot restore it.
Constraints
1 <= mccThresholds.length, merchants.length <= 10^3.- Every merchant ID and MCC is unique within its table; every merchant references a listed MCC.
0 <= events.length <= 10^4. Every event has one of the stated row shapes and every charge references a listed merchant.- Each code list contains at most
10^3unique codes. The lists are disjoint and every charge code is in exactly one list. - IDs and codes contain 1 through 40 ASCII letters, digits, or underscores. Comparisons are case-sensitive.
- Integer thresholds are decimal integers from
1through10^5. Ratio thresholds are decimal strings in(0, 1]with one through six digits after the decimal point. - A repeated charge ID repeats the original merchant and code. Every dispute references a preceding charge; disputes may repeat.
- The combined length of all input strings is at most
2 * 10^5characters. These bounds and validity guarantees define the practice input domain.