Reputation: 1498
I am working with this problem: https://www.hackerrank.com/challenges/fraudulent-activity-notifications/
My code works almost fine, but for some test cases it fails, because of the large array (over 200000 items). I am spending hours trying to understand what I can do to improve the speed, but I cannot come out with a working solution, so 2 of my tests always fail for timeout and I am frustrated trying to pass this test. I think I cannot avoid the first loop and also the loop in sort, but cannot think of a faster way.
The problem described in the website is is this:
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.
I solved it with this code
function getMedianNumber(arr) {
arr.sort((a, b) => a - b);
let medianNumber = 0;
const middle = Math.floor(arr.length / 2);
if (arr.length % 2 === 0) {
// Is even we get the median number
medianNumber = (arr[middle] + arr[middle - 1]) / 2;
} else {
const index = Math.floor(middle);
medianNumber = arr[index];
}
return medianNumber;
}
function activityNotifications(expenditure, d) {
let notifications = 0;
let len = expenditure.length - 1;
for (let i = len; i > d - 1; i--) {
let trailingDays = expenditure.slice(i - d, i);
let dayExpense = expenditure[i];
let median = getMedianNumber(trailingDays);
if (expenditure[i] >= median * 2) {
notifications++;
}
}
return notifications;
}
It only fails in 2 test cases because the passed array is huge and I get a timeout error.
Upvotes: 2
Views: 1360
Reputation: 11
function copy(a, ind) {
b = [];
for(var i = ind; i < a.length; ++i) {
b.push(a[i]);
}
return b;
}
function processData(input) {
//Enter your code here
var inputArr = input.split("\n");
var d = parseInt(inputArr[0].split(" ")[1]);
var arr = inputArr[1].split(" ").map(Number);
var countArray = [], sortedArray = [], tempArray = [], notifications = 0, median, count, middle;
for(var i = 0; i <= 200; ++i) {
countArray.push(0);
}
for(i = 0; i < d; ++i) {
countArray[arr[i]]++;
}
for(var j = 0; i < arr.length; ++i, ++j) {
tempArray = [], count = 0;
for(var k = 0; k <= 200; ++k) {
if(countArray[k] > 0) {
count += countArray[k];
tempArray.push({
no: k,
count: count
});
}
}
middle = {};
if((d&1) === 0) {
middle.index = count / 2;
} else {
middle.index = Math.ceil(count / 2);
}
var tempCount = 0;
for(k = 0; k < tempArray.length; ++k) {
if(tempArray[k].count === middle.index) {
if((d&1) === 0) {
median = (tempArray[k].no + tempArray[k + 1].no) / 2;
break;
} else {
median = tempArray[k].no;
break;
}
} else if(tempArray[k].count > middle.index) {
median = tempArray[k].no;
break;
}
}
//console.log(tempArray, median, arr[i]);
if(arr[i] >= (2 * median)) {
notifications++;
}
countArray[arr[i]]++;
countArray[arr[j]]--;
}
console.log(notifications);
}
process.stdin.resume();
process.stdin.setEncoding("ascii");
_input = "";
process.stdin.on("data", function (input) {
_input += input;
});
process.stdin.on("end", function () {
processData(_input);
});
Upvotes: 0
Reputation: 16068
expenditure.slice(i - d, i);
is too expensive, you are making it O(n^2) by copying the array elements over each iteration. Use indexes over the original array to calculate median: getMedianNumber(arr, startIndex, endIndex)
.
Upvotes: 2