欺诈活动通知HackerRank中的超时错误

时间:2019-10-06 12:39:42

标签: python python-3.x sorting functional-programming time-limiting

我正在解决此问题:Farudulent Activity Notification在HackerRank上。我已经完成了代码并可以工作,但是对于很大的输入来说,它也是低效的。

  

我不知道,但是经过我的所有努力,我能够为中等水平的问题提供很好的解决方案,但是对于大量输入,每次都会发生timeout error这个问题。我尝试优化代码,但仍然收到超时错误。   我针对这个问题和即将出现的问题的议程是:

     
      
  • 如何提高非常大的投入的效率。它需要什么样的智力。
  •   
  • 如何达到该水平。我应该为此做些什么。
  •   
  • 代码优化
  •   

我愿意学习,而且我非常渴望学习如何编写更高级和优化的代码以使自己变得更好。我愿意努力工作。

我的算法:

  
      
  1. 对于这个问题,我们必须从incrementing variable ilen(givenArray)-d
  2.   
  3. 为下一个要比较的变量取一个变量,我的情况iterate是变量
  4.   
  5. 将值传递到特定数组,以用于计算countFraud()的方法
  6.   
  7. 将其添加到计数变量
  8.   
  9. 增加迭代变量
  10.   

代码:

# this is for counting the trailing array
def countFraud(arr, nextNum):
    count = 0
    median = 0.0
    d = len(arr)
    #for calculating the median correctly
    arr.sort()
    if d%2 != 0:
        median = arr[int(d/2)]
    else:
        n = int(d/2)
        median = (arr[n] + arr[n-1]) / 2

    #now the opeartion for count from the array
    if nextNum >= 2*median: count += 1
    return count

# Complete the activityNotifications function below.
def activityNotifications(expenditure, d):
    count = 0
    iterate = d
    # it will go upto the len of array - d, so that it will go upto the d length
    # leaving the last element everytime for the comparision
    for i in range(len(expenditure)-d):
        count += countFraud(expenditure[i:iterate], expenditure[iterate])
        iterate += 1
    return count

现在,我之前做两个循环,将项目添加到new_array并将其传递到countFraud()。但是现在我已经对其进行了优化,并使其变得O(N)

我不知道,但是由于Timeout Error,此代码并未为所有TC提交。操作部分没有问题。只是有了代码的效率。

超时错误输入示例:

200000 10000

输入链接-Input Data

预期输出:

633

我已阅读本文:HackerRank Environment,以了解有关计时问题。对于 Python / Python 3 ,它是 10秒。我的代码肯定比values greater than 10^3 or 4需要更多的代码。

我的代码已成功通过了3个TC。请帮助。谢谢:)

7 个答案:

答案 0 :(得分:1)

我不知道为什么没有人提到中位数中位数算法,该算法从数组中查找中位数的复杂度为O(n),并且与数组的顺序无关。 >

答案 1 :(得分:1)

与您正在执行的操作类似,此方法使用两个功能:一个用于活动通知,另一个用于查找中位数。

找到中位数很容易。所使用的方法是检查支出中位数d的回溯天数是奇数还是偶数,然后根据该信息进行相应的计算。

然后,关于activityNotifications,关键是要知道支出[i]在0到200之间,包括两个数字(201)。

全部

def findMedian(counter, d):
    count = 0
    median = 0

    if d%2 != 0:
        for i in range(len(counter)):
            count += counter[i]

            if count > d//2:
                median = i
                break
            
    else:
        first = 0
        second = 0

        for i, _ in enumerate(counter):
            count += counter[i]
            
            if first == 0 and count >= d//2:
                first = i
                
            if second == 0 and count >= d//2 + 1:
                second = i
                break
            
        median = (first+second) / 2
        
    return median


def activityNotifications(expenditure, d):
    count = 0
    counter = [0]*201
    
    for exp in range(d):
        counter[expenditure[exp]] += 1

    for i in range(d, len(expenditure)):
        new = expenditure[i]
        old = expenditure[i-d]
        median = findMedian(counter, d)
        
        if new >= 2*median:
            count += 1
            
        counter[old] -= 1
        counter[new] += 1
        
    return count

这将通过HackerRank中的所有当前8个测试用例

It works Fraudulent Activity Notifications with Python

灵感来源:


请注意,Code Review中使用熊猫也有很好的答案。解决问题非常有趣,但在HackerRank中将无法使用

import pandas as pd

def activityNotifications(expenditure, d):
    df = pd.DataFrame(expenditure)
    return (df.shift(-1) > 2 * df.rolling(d).median())[0].sum()

答案 2 :(得分:0)

因为实际上没有人给我答案。我真的必须考虑排行榜中的解决方案。我发现每种解决方案都难以吸收,只有一种解决方案是好的。

免责声明::这是一种高级编码技术,因此在继续解决方案之前,您需要对语言有更好的了解。

解决方案的算法:

  
      
  1. 这需要两个数组,一个是t具有数组元素的总数,另一个是让我们将其命名为listD,只是排序后的first d elements
  2.   
  3. 返回包含前d个元素的列表的中值的函数
  4.   
  5. 循环从d开始直到n-1,if t[i] >= 2*median(): increment var noti
  6.   
  7. 使用PYTHON BISECT算法从listD中删除第一个元素,然后使用PYTHON INSORT算法将t[i]添加到listD中
  8.   
  9. 返回通知
  10.   

代码:

from bisect import bisect_left, insort_left

n, d = map(int, input().split())
t = list(map(int, input().split()))
noti = 0

listD = sorted(t[:d])

def median():
  return listD[d//2] if d%2 == 1 else ((listD[d//2] + listD[d//2-1])/2)

for i in range(d,n):
  if t[i] >= 2*median(): noti += 1
  del listD[bisect_left(listD, t[i-d])]
  insort_left(listD, t[i])
print(noti)

在这里,我们使用了BISECTINSORT,它们的作用基本上是返回要添加元素的位置,并在添加元素后返回排序列表。这样就减少了一次又一次地排序数组的麻烦,从而减少了时间复杂度并解决了所有测试用例。

您可以在这里阅读有关内容:Python Bisect and Insort Algo。谢谢,希望对以后的人有所帮助。

答案 3 :(得分:0)

这个通过了所有测试用例:-

    public static double findMedian(int a[]) {
        int n = a.length;
        if (n % 2 != 0)
            return (double) a[n / 2];

        return (double) (a[(n - 1) / 2] + a[n / 2]) / 2.0;
    }

    static void swap(int[] arr, int i, int j) {
        int temp = arr[i];
        arr[i] = arr[j];
        arr[j] = temp;
    }

    static int activityNotifications(int[] expenditure, int d) {
        if (d >= expenditure.length) return 0;

        int numNotifications = 0;
        int[] trailingArr = new int[d];
        for (int i = 0; i < trailingArr.length; i++) {
            trailingArr[i] = expenditure[i];
        }
        Arrays.sort(trailingArr);
        for (int i = d; i < expenditure.length; i++) {
            double median = findMedian(trailingArr);
            if (expenditure[i] >= 2.0 * median) {
                numNotifications += 1;
            }
            int nextToRemoveElement = expenditure[i - d];
            int toInsertElement = expenditure[i];
            adjustTrailingArray(trailingArr, nextToRemoveElement, toInsertElement);
        }
        return numNotifications;
    }

    //This whole thing is O(d) time. Note that we are not sorting again as trailing array was already sorted
    // as preprocessing and now only one new element has to find its position in sorted array.

    private static void adjustTrailingArray(int[] trailingArr, int elementToRemove, int elementToInsert) {
        if (elementToInsert == elementToRemove) return;
        int foundIndex = 0;

        //The first element of unsorted trailing array will move out of the sliding window
        //Since the trailing array was sorted by us, we have lost the position of its first element in original array.
        //Hence, I search linearly for it and replace it with the new element.

        while (foundIndex < trailingArr.length) {
            if (trailingArr[foundIndex] != elementToRemove) {
                foundIndex++;
            } else {
                trailingArr[foundIndex] = elementToInsert;
                break;
            }
        }

        //Now we bubble the new element just inserted using bubble sort to left/right based on whether it was bigger
        //or smaller than the element that got removed.

        if (elementToInsert > elementToRemove) {
            int i = foundIndex;
            while (i < trailingArr.length - 1) {
                if (trailingArr[i] > trailingArr[i + 1]) {
                    swap(trailingArr, i, i + 1);
                    i += 1;
                } else break;
            }
        } else {
            int i = foundIndex;
            while (i > 0) {
                if (trailingArr[i] < trailingArr[i - 1]) {
                    swap(trailingArr, i, i - 1);
                    i -= 1;
                } else break;
            }
        }
    }

答案 4 :(得分:0)

我们可以在这里使用计数排序技术。棘手的事情是,每次将范围向前移动时,我们都无法在此处对整个范围进行排序,因为这会增加时间复杂度,相反,我们应该只修改频率阵列,然后才能找到中值,简单地将频率范围中的频率相加即可。范围的开始直到和等于或大于d / 2。

这里需要注意的重要一点:奇数和偶数d的中位数略有不同。

int median(int arr[], int d)
{
    int med;
    
    int sum = 0;
    for(int i = 0; i <= 200; i++)
    {
        sum = sum + arr[i];
        if(sum>=d)
        {
            med = i;
            break;
        }
    }
    return med;
}

int activityNotifications(vector<int> expenditure, int d) {
    int count  = 0;
    int n = expenditure.size();
    if(n==d)
    {
        return 0;
    }
    int temp[201]={0};
    for(int i = 0; i < d; i++)
    {
        temp[expenditure[i]]++;
    }
    
    int med = median(temp, d/2+d%2);
    for(int i = d; i < n; i++)
    {
        if(d%2==0)
        {
            int temp_med = median(temp, d/2+1);
            if(expenditure[i]>=med+temp_med)
            {
                count++;
            }
        }
        else
        {
            if(expenditure[i]>=med*2)
            {
                count++;
            }
        }
        
        temp[expenditure[i-d]]--;
        temp[expenditure[i]]++;
        med = median(temp,d/2+d%2);
    }
    return count;
}

答案 5 :(得分:0)

简单得多

  1. 对于第一个窗口进行排序-占用O(dlog(d))

  2. 因为已经对其进行了排序,所以我们可以在每个下一个窗口中利用它 只需将新进入的号码替换为离开窗口的号码,然后从那里对它的正确位置进行排序-这需要-O(d)

总复杂度O(dlog(d)+(n-d-1)*(d))= O(nd)

对不起,如果代码看起来有点混乱

static int activityNotifications(int[] expenditure, int d) {
    int count = 0;
    int days = expenditure.length;
    int[]tempArr = Arrays.copyOfRange(expenditure,0,d);
    Arrays.sort(tempArr);//

    for(int i=0;d+i<days;i++){
        
       if(i>0 ){
      //rearrange them based on outgoing and incoming into the window
       int outgo = expenditure[i-1];
       int income = expenditure[i+d-1];
       rearrange(outgo,income,tempArr);}

    //get medain
     float median;
     int size= d;
     if(size%2==0){
        int mid = size/2;
       median = (float)(tempArr[mid-1]+tempArr[mid])/2;          
     }
    else{
        median = tempArr[size/2];
    }
   
    //checking notification         

        if(expenditure[d+i]>=2*median){
            count++;
        }

    }
return count;
}

公共静态无效空间重排(int outgo,int收入,int [] arr){

  int len = arr.length;
  int i=0;
  for( i=0;i<len;i++){
      if(arr[i]==outgo){
          arr[i]=income;
          break;
      }          
  }
  

if(i==0){        
 if(arr[i+1]>=income){return;}
 else{
      while(i+1<len  && arr[i+1]<income){
         arr[i]=arr[i+1];
         i++;
     }
     arr[i]=income;
 }
}
else if(i==len-1){
    if(arr[i-1]<=income){return;}
 else{
     while( i>=1 & arr[i-1]>income ){
         arr[i]=arr[i-1];
         i--;
     }
     arr[i]=income;
 }
 }


else{
    if(arr[i+1]<income){
         while(i+1<len  && arr[i+1]<income){
         arr[i]=arr[i+1];
         i++;
     }
     arr[i]=income;
    }
     if(arr[i-1]>income){

         while( i>=1 && arr[i-1]>income ){
         arr[i]=arr[i-1];
         i--;
     }
     arr[i]=income;            
    }
}

enter image description here

答案 6 :(得分:-1)

我在这个问题上花了很多时间,并提出了自己的新算法,并且给出了超过时限(TLE)的方法,并且仅通过了三个测试用例。

#include <iostream>
#include <cstring>
#include <cmath>
#include <cstring>
using namespace std;
int maxlen=1,minlen=1,heapsize;
double median=0,ct=0;
void min_heapify(double arr[],int i)
{
    int l=(2*i);
    int r=(2*i+1);
    int smallest;
    if(l<=heapsize && arr[l]<arr[i])
    {
        smallest=l;
    }
    else
    {
        smallest=i;
    }
    if(r<=heapsize && arr[r]<arr[smallest])
    {
        smallest=r;
    }
    if(smallest==i)
        return;
    if(smallest!=i)
    {
        double swap=arr[i];
        arr[i]=arr[smallest];
        arr[smallest]=swap;
    }
    min_heapify(arr,smallest);
}
void max_heapify(double arr[], int i)
{
    int l=(2*i);
    int r=(2*i+1);
    int largest;
    if(l<=heapsize && arr[l]>arr[i])
    {
        largest=l;
    }
    else
    {
        largest=i;
    }
    if(r<=heapsize && arr[r]>arr[largest])
    {
        largest=r;
    }
    if(largest==i)
        return;
    if(largest!=i)
    {
        double swap=arr[i];
        arr[i]=arr[largest];
        arr[largest]=swap;
    }
    max_heapify(arr,largest);
}
void insert_valuein_minheap(double minh[], int i, double val)
{
    minh[i]=val;
    while(i>1 && minh[i/2]>minh[i])
    {
        double temp=minh[i/2];
        minh[i/2]=minh[i];
        minh[i]=temp;
        i=i/2;
    }
}
void insert_valuein_maxheap(double maxh[], int i, double val)
{
    maxh[i]=val;
    while(i>1 && maxh[i/2]<maxh[i])
    {
        double temp=maxh[i/2];
        maxh[i/2]=maxh[i];
        maxh[i]=temp;
        i=i/2;
    }
}
void insert_element(double maxh[], double minh[], double val, int size)
{
    if(val<=maxh[1])
    {
        maxlen+=1;
        insert_valuein_maxheap(maxh,maxlen,val);
    }
    else
    {
        minlen+=1;
        insert_valuein_minheap(minh,minlen,val);
    }
    if(maxlen==minlen)
    {
        median=(maxh[1]+minh[1])/2;
        ct=1;
        return;
    }
    if(maxlen<minlen)
    {
        maxlen+=1;
        insert_valuein_maxheap(maxh,maxlen,minh[1]);
        double temp=minh[1];
        minh[1]=minh[minlen];
        minh[minlen]=temp;
        minlen-=1;
        heapsize=minlen;
        min_heapify(minh,1);
    }
    else
    {
        minlen+=1;
        insert_valuein_minheap(minh,minlen,maxh[1]);
        double temp=maxh[1];
        maxh[1]=maxh[maxlen];
        maxh[maxlen]=temp;
        maxlen-=1;
        heapsize=maxlen;
        max_heapify(maxh,1);
    }
}
int main()
{
    int n,td,notif=0;
    cin>>n>>td;
    double array[n+1],maxh[n+1]={},minh[n+1]={};
    for(int i=1;i<=n;i++)
    {
        cin>>array[i];
    }
    double first,second;
    for(int i=1,j;i<=n-td;i++)
    {
        int count=2;
        first=array[i];
        second=array[i+1];
        if(first<=second)
        {
            maxh[1]=first;
            minh[1]=second;
        }
        else
        {
            maxh[1]=first;
            minh[1]=second;
        }
        maxlen=1;minlen=1;ct=0;
        for(j=i+2;count!=td;j++)
        {
            insert_element(maxh,minh,array[j],j);
            count++;
        }
        if(td%2!=0)
        {
            if(maxlen>minlen)
                median=maxh[1];
            else
                median=minh[1];
        }
        else if(ct==0)
        {
            median=(maxh[1]+minh[1])/2;
        }
        float nota=array[j];
        if(nota>=2*median)
        {
            notif++;
        }
    }
    cout<<notif<<endl;
}