Fraudulent Activity Notifications

  • + 0 comments
    • my solution for JS, worked for me on all test-cases
    • with explanation due to JS being very slow on high-load-operations
    function activityNotifications(expenditure, d) {
      // Write your code here
      let notificationCounter = 0;
      const middle = Math.ceil(d / 2);
      
      // sort first trailing days, use this as base for future operations and to calculate the median
      const sortedTrailingDays = expenditure
        .slice(0, d)
        .sort((a, b) => (b < a ? 0 : -1));
    
      for (let i = d; i < expenditure.length; i++) {
        const spentThisDay = expenditure[i];
    
        if (i > d) { // ignore first iteration, trailings days are sorted once before the loop
          /**
           * 2 operations on the sorted array of trailing day expenditures
           *    1. remove the expenditure of the day that dropped out of the trailing days
           *    2. add the expenditure of the previous day to the trailing days at the correct position
           * 
           * this is way faster than sorting the whole array on every iteration 
           * with the js-array-sort method (as done above the for-loop)
           *  -> this way the function was fast enough to succeed all test-cases, 
           *     even in slow-ass single-CPU-javascript :D
           */
          // remove "dropped out" number/day
          sortedTrailingDays.splice(
            sortedTrailingDays.indexOf(expenditure[i - d - 1]),
            1
          );
          // insert "previous-day-expenditure" to sorted array at the correct position
          const spentDayBefore = expenditure[i - 1];
          if (spentDayBefore <= sortedTrailingDays[0]) {
            sortedTrailingDays.unshift(spentDayBefore); // first pos
          } else if (
            spentDayBefore >= sortedTrailingDays[sortedTrailingDays.length - 1]
          ) {
            sortedTrailingDays.push(spentDayBefore);  // last pos
          } else {
            // find first higher number -> insert there
            const idx = sortedTrailingDays.indexOf(
              sortedTrailingDays.find((n) => n > spentDayBefore) // most likely to slow for testcase-5
            );
            sortedTrailingDays.splice(idx, 0, spentDayBefore);
          }
        }
        
        // calculate median
        const median = d % 2 === 0 ? 
            (sortedTrailingDays[middle] + sortedTrailingDays[middle - 1]) / 2 
            : sortedTrailingDays[middle - 1];
    
        if (spentThisDay >= median * 2) {
          notificationCounter++;
        }
      }
    
      return notificationCounter;
    }