Hackerrank Fraudulent Activity Notifications Solution

Hackerrank Fraudulent Activity Notifications Solution

.MathJax_SVG_Display {text-align: center; margin: 1em 0em; position: relative; display: block!important; text-indent: 0; max-width: none; max-height: none; min-width: 0; min-height: 0; width: 100%} .MathJax_SVG .MJX-monospace {font-family: monospace} .MathJax_SVG .MJX-sans-serif {font-family: sans-serif} .MathJax_SVG {display: inline; font-style: normal; font-weight: normal; line-height: normal; font-size: 100%; font-size-adjust: none; text-indent: 0; text-align: left; text-transform: none; letter-spacing: normal; word-spacing: normal; word-wrap: normal; white-space: nowrap; float: none; direction: ltr; max-width: none; max-height: none; min-width: 0; min-height: 0; border: 0; padding: 0; margin: 0} .MathJax_SVG * {transition: none; -webkit-transition: none; -moz-transition: none; -ms-transition: none; -o-transition: none} .mjx-svg-href {fill: blue; stroke: blue} .MathJax_SVG_LineBox {display: table!important} .MathJax_SVG_LineBox span {display: table-cell!important; width: 10000em!important; min-width: 0; max-width: none; padding: 0; border: 0; margin: 0}

HackerLand National Bank has a simple policy for warning clients about possible fraudulent account activity. If the amount spent by a client on a particular day is greater than or equal to  the client's median spending for a trailing number of days, they send the client a notification about potential fraud. The bank doesn't send the client any notifications until they have at least that trailing number of prior days' transaction data.

Given the number of trailing days  and a client's total daily expenditures for a period of  days, find and print the number of times the client will receive a notification over all  days.

For example,  and .  On the first three days, they just collect spending data.  At day , we have trailing expenditures of .  The median is  and the day's expenditure is .  Because , there will be a notice.  The next day, our trailing expenditures are  and the expenditures are .  This is less than  so no notice will be sent.  Over the period, there was one notice sent.

Note: The median of a list of numbers can be found by arranging all the numbers from smallest to greatest. If there is an odd number of numbers, the middle one is picked. If there is an even number of numbers, median is then defined to be the average of the two middle values. (Wikipedia)

Function Description

Complete the function activityNotifications in the editor below.  It must return an integer representing the number of client notifications.

activityNotifications has the following parameter(s):

  • expenditure: an array of integers representing daily expenditures
  • d: an integer, the lookback days for median spending

Input Format.MathJax_SVG_Display {text-align: center; margin: 1em 0em; position: relative; display: block!important; text-indent: 0; max-width: none; max-height: none; min-width: 0; min-height: 0; width: 100%} .MathJax_SVG .MJX-monospace {font-family: monospace} .MathJax_SVG .MJX-sans-serif {font-family: sans-serif} .MathJax_SVG {display: inline; font-style: normal; font-weight: normal; line-height: normal; font-size: 100%; font-size-adjust: none; text-indent: 0; text-align: left; text-transform: none; letter-spacing: normal; word-spacing: normal; word-wrap: normal; white-space: nowrap; float: none; direction: ltr; max-width: none; max-height: none; min-width: 0; min-height: 0; border: 0; padding: 0; margin: 0} .MathJax_SVG * {transition: none; -webkit-transition: none; -moz-transition: none; -ms-transition: none; -o-transition: none} .mjx-svg-href {fill: blue; stroke: blue} .MathJax_SVG_LineBox {display: table!important} .MathJax_SVG_LineBox span {display: table-cell!important; width: 10000em!important; min-width: 0; max-width: none; padding: 0; border: 0; margin: 0}

The first line contains two space-separated integers  and , the number of days of transaction data, and the number of trailing days' data used to calculate median spending.
The second line contains  space-separated non-negative integers where each integer  denotes .

Constraints.MathJax_SVG_Display {text-align: center; margin: 1em 0em; position: relative; display: block!important; text-indent: 0; max-width: none; max-height: none; min-width: 0; min-height: 0; width: 100%} .MathJax_SVG .MJX-monospace {font-family: monospace} .MathJax_SVG .MJX-sans-serif {font-family: sans-serif} .MathJax_SVG {display: inline; font-style: normal; font-weight: normal; line-height: normal; font-size: 100%; font-size-adjust: none; text-indent: 0; text-align: left; text-transform: none; letter-spacing: normal; word-spacing: normal; word-wrap: normal; white-space: nowrap; float: none; direction: ltr; max-width: none; max-height: none; min-width: 0; min-height: 0; border: 0; padding: 0; margin: 0} .MathJax_SVG * {transition: none; -webkit-transition: none; -moz-transition: none; -ms-transition: none; -o-transition: none} .mjx-svg-href {fill: blue; stroke: blue} .MathJax_SVG_LineBox {display: table!important} .MathJax_SVG_LineBox span {display: table-cell!important; width: 10000em!important; min-width: 0; max-width: none; padding: 0; border: 0; margin: 0}

Output Format.MathJax_SVG_Display {text-align: center; margin: 1em 0em; position: relative; display: block!important; text-indent: 0; max-width: none; max-height: none; min-width: 0; min-height: 0; width: 100%} .MathJax_SVG .MJX-monospace {font-family: monospace} .MathJax_SVG .MJX-sans-serif {font-family: sans-serif} .MathJax_SVG {display: inline; font-style: normal; font-weight: normal; line-height: normal; font-size: 100%; font-size-adjust: none; text-indent: 0; text-align: left; text-transform: none; letter-spacing: normal; word-spacing: normal; word-wrap: normal; white-space: nowrap; float: none; direction: ltr; max-width: none; max-height: none; min-width: 0; min-height: 0; border: 0; padding: 0; margin: 0} .MathJax_SVG * {transition: none; -webkit-transition: none; -moz-transition: none; -ms-transition: none; -o-transition: none} .mjx-svg-href {fill: blue; stroke: blue} .MathJax_SVG_LineBox {display: table!important} .MathJax_SVG_LineBox span {display: table-cell!important; width: 10000em!important; min-width: 0; max-width: none; padding: 0; border: 0; margin: 0}

Print an integer denoting the total number of times the client receives a notification over a period of  days.

Sample Input 0

9 5
2 3 4 2 3 6 8 4 5

Sample Output 0

2

Explanation 0

We must determine the total number of  the client receives over a period of  days. For the first five days, the customer receives no notifications because the bank has insufficient transaction data: .

On the sixth day, the bank has  days of prior transaction data, , and  dollars. The client spends  dollars, which triggers a notification because : .

On the seventh day, the bank has  days of prior transaction data, , and  dollars. The client spends  dollars, which triggers a notification because :  .

On the eighth day, the bank has  days of prior transaction data, , and  dollars. The client spends  dollars, which does not trigger a notification because : .

On the ninth day, the bank has  days of prior transaction data, , and a transaction median of  dollars. The client spends  dollars, which does not trigger a notification because : .

Sample Input 1

5 4
1 2 3 4 4

Sample Output 1

0

There are  days of data required so the first day a notice might go out is day .  Our trailing expenditures are  with a median of   The client spends  which is less than  so no notification is sent.

Solution in java8

Approach 1.

import java.io.*;
import java.math.*;
import java.security.*;
import java.text.*;
import java.util.*;
import java.util.concurrent.*;
import java.util.regex.*;
import java.util.Scanner;

public class FraudulentActivityNotifications {
static int getMedian(int freq[],int d){
        int prefix_sum[] = new int[201];
        prefix_sum[0] = freq[0];
        for(int i=1;i<201;i++){
            prefix_sum[i] = prefix_sum[i-1] + freq[i];
        }
        int median;
        int a = 0;
        int b = 0;
        if(d%2==0){
            int first = d/2;
            int second = first+1;
            int i = 0;
            for(;i<201;i++){
                if(first<=prefix_sum[i]){
                    a = i;
                    break;
                }
            }
            for(;i<201;i++){
                if(second<=prefix_sum[i]){
                    b = i;
                    break;
                }
            }

        }else{
            int first = d/2 + 1;
            for(int i=0;i<201;i++){
                if(first<=prefix_sum[i]){
                    a = i;
                    break;
                }
            }
        }
        median = a + b;
        return median;
    }


    public static void showingNotifications() {
        Scanner scanner = new Scanner(System.in);
        int n = scanner.nextInt();
        int d = scanner.nextInt();
        int arr[] = new int[n];
        for (int i = 0; i < n; i++)
            arr[i] = scanner.nextInt();
        int total = 0;
        int freq[] = new int[201];
        boolean first_time = true;
        int pop_element = 0;
        for (int index = d; index < n; index++) {
            if (first_time) {
                first_time = false;
                for (int i = index - d; i <= index - 1; i++)
                    freq[arr[i]]++;
            } else {
                freq[pop_element]--;
                freq[arr[index - 1]]++;
            }
            int median = getMedian(freq, d);
            if (d % 2 == 0) {
                if (arr[index] >= median)
                    total++;
            } else {
                if (arr[index] >= 2 * median)
                    total++;
            }
            pop_element = arr[index - d];
        }
        System.out.println(total);
    }

    public static void main(String[] args) {
        showingNotifications();
    }
}


Approach 2.

import java.io.*;
import java.math.*;
import java.security.*;
import java.text.*;
import java.util.*;
import java.util.concurrent.*;
import java.util.regex.*;

public class Solution {

    // Complete the activityNotifications function below.
    static int activityNotifications(int[] expenditure, int d) {
        int start=0,mid1,mid2,count=0;
        float median;
        mid2=d/2+1;
        
        if(d%2==0)
            mid1= mid2-1; 
        else
            mid1= mid2;
        System.out.println("mid1= "+mid1+" mid2= "+ mid2);
        int[] countArr = new int[201];
 
        for(int i=0;i<d;i++) {
            ++countArr[expenditure[i]];
        }
        
        for(int i=d;i<expenditure.length;i++) {
            median = findMedian(countArr, mid1,mid2);
            System.out.print(" median= "+ median);
            if(expenditure[i]>=median*2)
                count++;
            --countArr[expenditure[start]];
            start++;
            ++countArr[expenditure[i]];
        }
        
        return count;
    }

    static public float findMedian(int[] arr, int mid1,int mid2) {
        int count=0, temp1=0,temp2=0,i=0;
        while(count<mid1) {
//            System.out.println("arr[i]= "+ )
            count += arr[i];
            i++;
        }
 //       System.out.print("arr[i]="+arr[i]+ " i= "+i);
        System.out.print(" count= "+ count+" i= "+ i);
        temp1=i-1;
        while(count<mid2) {
            count += arr[i];
            i++;
        }
        temp2 = i-1;
  //      System.out.println(" i= "+i);
 //   System.out.print("arr[10] = "+ arr[10]);
        return (temp1+temp2)/(float)2.0;
    }

    private static final Scanner scanner = new Scanner(System.in);

    public static void main(String[] args) throws IOException {
        BufferedWriter bufferedWriter = new BufferedWriter(new FileWriter(System.getenv("OUTPUT_PATH")));

        String[] nd = scanner.nextLine().split(" ");

        int n = Integer.parseInt(nd[0]);

        int d = Integer.parseInt(nd[1]);

        int[] expenditure = new int[n];

        String[] expenditureItems = scanner.nextLine().split(" ");
        scanner.skip("(\r\n|[\n\r\u2028\u2029\u0085])?");

        for (int i = 0; i < n; i++) {
            int expenditureItem = Integer.parseInt(expenditureItems[i]);
            expenditure[i] = expenditureItem;
        }

        int result = activityNotifications(expenditure, d);

        bufferedWriter.write(String.valueOf(result));
        bufferedWriter.newLine();

        bufferedWriter.close();

        scanner.close();
    }
}

Approach 3.

import java.io.*;
import java.math.*;
import java.security.*;
import java.text.*;
import java.util.*;
import java.util.concurrent.*;
import java.util.regex.*;

public class Solution {

    static int activityNotifications(Integer[] expenditure, int d) {
        int median=0;
        int notifications=0;
        int[] frequency=new int[201];
        Queue<Integer> q=new LinkedList<>();
        boolean odd=true;
        if((d%2)==0)
        odd=false;
        for(int i=0;i<d;i++){
            frequency[expenditure[i]]++;
            q.add(expenditure[i]);
        }
        if(odd){
            for(int i=d;i<expenditure.length;i++){
                int j=0;
                int k=-1;
                while(j<=(d/2)){
                    k++;
                    j+=frequency[k];
                }
                median=k;
                if(expenditure[i]>=(2*median)){
                notifications++;
                }
                int node=q.remove();
                q.add(expenditure[i]);
                frequency[expenditure[i]]++;
                frequency[node]--;
            }

        }
        else{
            for(int i=d;i<expenditure.length;i++){
                int j=0;
                int k=-1;
                while(j<(d/2)){
                    k++;
                    j+=frequency[k];
                }
                if(j>(d/2)){
                median=k;
                if(expenditure[i]>=(2*median))
                notifications++;
                }
                else if(j==(d/2)){
                    int previous=k;
                    k++;
                while(frequency[k]<1){
                    k++;
                }
                median=((previous+k)/2);
                    if(expenditure[i]>=((2*median)+1))
                notifications++;      
        }
        int node=q.remove();
                q.add(expenditure[i]);
                frequency[expenditure[i]]++;
                frequency[node]--;
        }
        }
    return notifications;
    }

    private static final Scanner scanner = new Scanner(System.in);

    public static void main(String[] args) throws IOException {

        String[] nd = scanner.nextLine().split(" ");

        int n = Integer.parseInt(nd[0]);

        int d = Integer.parseInt(nd[1]);

        Integer[] expenditure = new Integer[n];

        String[] expenditureItems = scanner.nextLine().split(" ");
        scanner.skip("(\r\n|[\n\r\u2028\u2029\u0085])?");

        for (int i = 0; i < n; i++) {
            int expenditureItem = Integer.parseInt(expenditureItems[i]);
            expenditure[i] = expenditureItem;
        }

        int result = activityNotifications(expenditure, d);

       System.out.println(result);

        scanner.close();
    }
}

Solution in python3

Approach 1.

#!/bin/python3

import math
import os
import random
import re
import sys

# Complete the activityNotifications function below.
from bisect import insort, bisect_left
def activityNotifications(expenditure, d):
    v = sorted(expenditure[: d])
    count = 0
    for i, current in enumerate(expenditure[d:]):
        de = expenditure[i]
        if d%2 == 0:
            if current >= v[d//2] + v[d//2-1]:
                count += 1
        elif current >= v[d//2]*2:
                count += 1
        ix = bisect_left(v, de)
        del v[ix]
        insort(v, current)
    return count

if __name__ == '__main__':
    fptr = open(os.environ['OUTPUT_PATH'], 'w')

    nd = input().split()

    n = int(nd[0])

    d = int(nd[1])

    expenditure = list(map(int, input().rstrip().split()))

    result = activityNotifications(expenditure, d)

    fptr.write(str(result) + '\n')

    fptr.close()

Approach 2.

#!/bin/python3

import math
import os
import random
import re
import sys

# Complete the activityNotifications function below.
 
from bisect import insort, bisect_left
def activityNotifications(expenditure, d):
    v = sorted(expenditure[: d])
    count = 0
    for i, current in enumerate(expenditure[d:]):
        de = expenditure[i]
        if d%2 == 0:
            if current >= v[d//2] + v[d//2-1]:
                count += 1
        elif current >= v[d//2]*2:
                count += 1
        ix = bisect_left(v, de)
        del v[ix]
        insort(v, current)
    return count
if __name__ == '__main__':
    fptr = open(os.environ['OUTPUT_PATH'], 'w')

    nd = input().split()

    n = int(nd[0])

    d = int(nd[1])

    expenditure = list(map(int, input().rstrip().split()))

    result = activityNotifications(expenditure, d)

    fptr.write(str(result) + '\n')

    fptr.close()

Approach 3.

#!/bin/python3

import math
import os
import random
import re
import sys
 
def getMedian(n,count):
    tot = 0
    if n % 2 == 1:
        for i,c in enumerate(count):
            tot += c
            if tot > n//2:
                return i
    else:
        for i,c in enumerate(count):
            tot += c
            if tot >= n/2:
                if tot > n/2:
                    return i
                j = i + 1
                while count[j] == 0:
                    j += 1
                return (i + j)/2

def activityNotifications(expenditure, d):
    length = len(expenditure)
    count = [0 for _ in range(200+1)]
    ilegal = 0
    if d >= length:
        return 0
    for n in expenditure[:d]:
        count[n] += 1
    i = d
    while i < length:
        median = getMedian(d,count)
        if expenditure[i] >= median*2:
            ilegal += 1
        count[expenditure[i]] += 1
        count[expenditure[i-d]] -= 1
        i += 1
    return ilegal
if __name__ == '__main__':
    fptr = open(os.environ['OUTPUT_PATH'], 'w')

    nd = input().split()

    n = int(nd[0])

    d = int(nd[1])

    expenditure = list(map(int, input().rstrip().split()))

    result = activityNotifications(expenditure, d)

    fptr.write(str(result) + '\n')

    fptr.close()

Solution in cpp

Approach 1.

#include <stdio.h>
#include <string.h>
#include <math.h>
#include <stdlib.h>

int main() {
    int n;
    int d;
    scanf("%d %d", &n, &d);

    int* arr = (int*) malloc(n * sizeof(int));
    int* sort_arr = (int*) calloc(201, sizeof(int));

    for (int i = 0; i < n; i++) {
        scanf("%d", &(arr[i]));
    }

    int d_even = d % 2 == 0;

    int d_half;
    if (d_even) {
        d_half = (d / 2);
    } else {
        d_half = ceil((float)d / 2.0f);
    }

    int announcements = 0;
    for (int i = 0; i < n; i++) {
        if (i >= d) {
            int j = 0;
            int h = 0;
            float median = 0;
            int median_valid = 0;
            while (!median_valid) {
                if (h + sort_arr[j] >= d_half && !d_even) {
                    median = j;
                    median_valid = 1;
                }

                if (h + sort_arr[j] >= d_half && median == 0 && d_even) {
                    median = j;
                }

                if (h + sort_arr[j] >= d_half + 1 && d_even) {
                    median += j;
                    median = median / 2;
                    median_valid = 1;
                }

                h += sort_arr[j];

                j++;
            }

            if (arr[i] >= median * 2.0f) {
                announcements++;
            }

            sort_arr[arr[i - d]]--;
        }

        sort_arr[arr[i]]++;
    }

    printf("%d\n", announcements);

    free(arr);
    free(sort_arr);

    return 0;
}


Approach 2.

#include <bits/stdc++.h>

using namespace std;

vector<string> split_string(string);

int get(vector<int> &am, int t, bool mid){
  int acum=0;
  for(int i=0;i<=200;i++){
    acum+=am[i];
    if(acum>=t){
      if(!mid)return 2*i;
      if(acum>t) return 2*i;
      for(int j=i+1;j<=200;j++) if(am[j]) return i+j;
    }
  }
  assert(0);
}

// Complete the activityNotifications function below.
int activityNotifications(vector<int> v, int d) {
  int ans=0,n=v.size();
  vector<int> am(201);
  for(int i=0;i<n;i++){
    if(i>=d){
      int m=get(am,(d+1)/2,d%2==0);
      ans += m<=v[i];
      am[v[i-d]]--;
    }
    am[v[i]]++;
  }
  return ans;

}

int main()
{
    ofstream fout(getenv("OUTPUT_PATH"));

    string nd_temp;
    getline(cin, nd_temp);

    vector<string> nd = split_string(nd_temp);

    int n = stoi(nd[0]);

    int d = stoi(nd[1]);

    string expenditure_temp_temp;
    getline(cin, expenditure_temp_temp);

    vector<string> expenditure_temp = split_string(expenditure_temp_temp);

    vector<int> expenditure(n);

    for (int i = 0; i < n; i++) {
        int expenditure_item = stoi(expenditure_temp[i]);

        expenditure[i] = expenditure_item;
    }

    int result = activityNotifications(expenditure, d);

    fout << result << "\n";

    fout.close();

    return 0;
}

vector<string> split_string(string input_string) {
    string::iterator new_end = unique(input_string.begin(), input_string.end(), [] (const char &x, const char &y) {
        return x == y and x == ' ';
    });

    input_string.erase(new_end, input_string.end());

    while (input_string[input_string.length() - 1] == ' ') {
        input_string.pop_back();
    }

    vector<string> splits;
    char delimiter = ' ';

    size_t i = 0;
    size_t pos = input_string.find(delimiter);

    while (pos != string::npos) {
        splits.push_back(input_string.substr(i, pos - i));

        i = pos + 1;
        pos = input_string.find(delimiter, i);
    }

    splits.push_back(input_string.substr(i, min(pos, input_string.length()) - i + 1));

    return splits;
}

Approach 3.

#include <bits/stdc++.h>

using namespace std;

vector<string> split_string(string);

// Complete the activityNotifications function below.
int activityNotifications(vector<int> expenditure, int d) {
  int numOfNotificatios = 0;
  vector<int> t(d);

  for (int i = 0; i < d; i++) {
    t[i] = expenditure[i];
  }
  sort(t.begin(), t.end());

  for (int i = d; i < expenditure.size(); i++) {
    double med = 0;
    if ((d % 2) == 0) {
      med = (double)(t[d / 2 - 1] + t[d / 2]) / 2;
    } else {
      med = t[d / 2];
    }
    if (expenditure[i] >= 2 * med) {
      numOfNotificatios += 1;
    }
    // insert next element:
    t.erase(lower_bound(t.begin(), t.end(), expenditure[i - d]));
    t.emplace(upper_bound(t.begin(), t.end(), expenditure[i]), expenditure[i]);
  }

  return numOfNotificatios;
}

int main()
{
    ofstream fout(getenv("OUTPUT_PATH"));

    string nd_temp;
    getline(cin, nd_temp);

    vector<string> nd = split_string(nd_temp);

    int n = stoi(nd[0]);

    int d = stoi(nd[1]);

    string expenditure_temp_temp;
    getline(cin, expenditure_temp_temp);

    vector<string> expenditure_temp = split_string(expenditure_temp_temp);

    vector<int> expenditure(n);

    for (int i = 0; i < n; i++) {
        int expenditure_item = stoi(expenditure_temp[i]);

        expenditure[i] = expenditure_item;
    }

    int result = activityNotifications(expenditure, d);

    fout << result << "\n";

    fout.close();

    return 0;
}

vector<string> split_string(string input_string) {
    string::iterator new_end = unique(input_string.begin(), input_string.end(), [] (const char &x, const char &y) {
        return x == y and x == ' ';
    });

    input_string.erase(new_end, input_string.end());

    while (input_string[input_string.length() - 1] == ' ') {
        input_string.pop_back();
    }

    vector<string> splits;
    char delimiter = ' ';

    size_t i = 0;
    size_t pos = input_string.find(delimiter);

    while (pos != string::npos) {
        splits.push_back(input_string.substr(i, pos - i));

        i = pos + 1;
        pos = input_string.find(delimiter, i);
    }

    splits.push_back(input_string.substr(i, min(pos, input_string.length()) - i + 1));

    return splits;
}

Subscribe to The Poor Coder | Algorithm Solutions

Don’t miss out on the latest issues. Sign up now to get access to the library of members-only issues.
[email protected]
Subscribe