可以将文章内容翻译成中文,广告屏蔽插件可能会导致该功能失效(如失效,请关闭广告屏蔽插件后再试):
问题:
I have the following problem:
You are given N counters, initially set to 0, and you have two possible operations on them:
A non-empty zero-indexed array A of M integers is given. This array represents consecutive operations:
- if A[K] = X, such that 1 ≤ X ≤ N, then operation K is increase(X),
- if A[K] = N + 1 then operation K is max_counter.
For example, given integer N = 5 and array A such that:
A[0] = 3 A[1] = 4 A[2] = 4 A[3] = 6 A[4] = 1 A[5] = 4 A[6] = 4
the values of the counters after each consecutive operation will be:
(0, 0, 1, 0, 0) (0, 0, 1, 1, 0) (0, 0, 1, 2, 0) (2, 2, 2, 2, 2) (3, 2, 2, 2, 2) (3, 2, 2, 3, 2) (3, 2, 2, 4, 2)
The goal is to calculate the value of every counter after all operations.
I did the following solution but it runs at O(NK) where K = length of array A.
public int[] solution(int N, int[] A) { int[] result = new int[N]; int maximum = 0; for (int K = 0; K < A.Length; K++) { if (A[K] < 1 || A[K] > N + 1) throw new InvalidOperationException(); if (A[K] >= 1 && A[K] <= N) { result[A[K] - 1]++; if (result[A[K] - 1] > maximum) { maximum = result[A[K] - 1]; } } else { // inefficiency here for (int i = 0; i < result.Length; i++) result[i] = maximum; } } return result; }
Could anyone show me how this can be better done with O(N + K) where K is the length of array A? Sorry for may terrible coding, I am doing these exercises to improve my programming. Thanks!
回答1:
This is what I came up with, but I am not sure if it works 100%:
public int[] solution(int N, int[] A) { int[] result = new int[N]; int maximum = 0; int resetLimit = 0; for (int K = 0; K < A.Length; K++) { if (A[K] < 1 || A[K] > N + 1) throw new InvalidOperationException(); if (A[K] >= 1 && A[K] <= N) { if (result[A[K] - 1] < resetLimit) { result[A[K] - 1] = resetLimit + 1; } else { result[A[K] - 1]++; } if (result[A[K] - 1] > maximum) { maximum = result[A[K] - 1]; } } else { // inefficiency here //for (int i = 0; i < result.Length; i++) // result[i] = maximum; resetLimit = maximum; } } for (int i = 0; i < result.Length; i++) result[i] = Math.Max(resetLimit, result[i]); return result; }
回答2:
def solution(N, A): # write your code in Python 2.6 res = [0] * N m = 0 minValue = 0 for x in A: if 1 <= x <= N: res[x - 1] = max(res[x - 1], minValue) + 1 if res[x - 1] > m: m = res[x - 1] else: minValue = m for i in xrange(N): res[i] = max(res[i], minValue) return res
回答3:
Here's a solution I came up with in Python (100/100 on codility); it's a little different than others I've seen on here so thought I'd share:
def solution(N, A): count = [0] * N max_counter = [i for i, a in enumerate(A) if a == N+1] if len(max_counter) == len(A): return count if max_counter: mode = 0 for i, m in enumerate(max_counter): if m == 0 or m - max_counter[i-1] == 1: continue subcount = {} if i == 0: for k in A[:m]: if k not in subcount: subcount[k] = 1 else: subcount[k] += 1 else: for k in A[max_counter[i-1]+1:m]: if k not in subcount: subcount[k] = 1 else: subcount[k] += 1 mode += max(subcount.values()) count = [mode] * N for k in A[max_counter[-1]+1:]: count[k-1] += 1 else: for k in A: count[k-1] += 1 return count
回答4:
Remember:
"Making your code readable is as important as making it executable."
-- Robert C Martin
Even when trying to solve a hard problem...
So trying to achieve a better readability I've created a class to encapsulate the counters array and its operations (Law of Demeter). Sadly my first solution got only 60% in the performance test, so at the cost of a bit of readability I've improved it with a smarter solution and finally got 100%.
Here are my two implementations with comments:
O(N*M) Correctness 100% / Performance 60% (high redability)
//I didn't refactored the names of the variables N and A //to maintain it aligned with the question description public int[] solution(int N, int[] A) { var counters = new Counters(N); for (int k = 0; k < A.Length; k++) { if (A[k] <= N) counters.IncreaseCounter(A[k]); else counters.MaxAllCounters(); } return counters.ToArray(); } public class Counters { private int[] counters; private int greaterValueInCounter = 0; public Counters(int length) { counters = new int[length]; } public void MaxAllCounters() { for (int i = 0; i < counters.Length; i++) { counters[i] = greaterValueInCounter; } } public void IncreaseCounter(int counterPosition) { //The counter is one-based, but our array is zero-based counterPosition--; //Increments the counter counters[counterPosition]++; if (counters[counterPosition] > greaterValueInCounter) greaterValueInCounter = counters[counterPosition]; } //The counters array is encapsuled in this class so if we provide external //acess to it anyone could modify it and break the purpose of the encapsulation //So we just exposes a copy of it :) public int[] ToArray() { return (int[])counters.Clone(); } }
Codility result
O(N+M) Correctness 100% / Performance 100% (not so high redability)
Note the beauty of the encapsulation: to improve the algorithm I just have to edit some methods of the Counters
class without changing a single character on the solution
method.
Methods edited in the Counters
class:
IncreaseCounter()
MaxAllCounters()
ToArray()
Final code:
//Exactly the same code public int[] solution(int N, int[] A) { var counters = new Counters(N); for (int k = 0; k < A.Length; k++) { if (A[k] <= N) counters.IncreaseCounter(A[k]); else counters.MaxAllCounters(); } return counters.ToArray(); } public class Counters { private int[] counters; private int greaterValueInCounter = 0; private int currentEquilibratedScore = 0; public Counters(int length) { counters = new int[length]; } public void MaxAllCounters() { //We don't update the entire array anymore - that was what caused the O(N*M) //We just save the current equilibrated score value currentEquilibratedScore = greaterValueInCounter; } public void IncreaseCounter(int counterPosition) { //The counter is one-based, but our array is zero-based counterPosition--; //We need to add this "if" here because with this new solution the array //is not always updated, so if we detect that this position is lower than //the currentEquilibratedScore, we update it before any operation if (counters[counterPosition] < currentEquilibratedScore) counters[counterPosition] = currentEquilibratedScore + 1; else counters[counterPosition]++; if (counters[counterPosition] > greaterValueInCounter) greaterValueInCounter = counters[counterPosition]; } //The counters array is encapsuled in this class so if we provide external //acess to it anyone could modify it and break the purpose of the encapsulation //So we just exposes a copy of it :) public int[] ToArray() { //Now we need to fix the unupdated values in the array //(the values that are less than the equilibrated score) for (int i = 0; i < counters.Length; i++) { if (counters[i] < currentEquilibratedScore) counters[i] = currentEquilibratedScore; } return (int[])counters.Clone(); } }
Codility result
回答5:
Let's see...
public int[] Solution(int N, int[] A) { int[] data = new int[N]; int maxval = 0; int baseval = 0; for (int K = 0; K < A.length; K++) { int index = A[K] - 1; if (index < 0 || index > N) throw new InvalidOperationException(); if (index < N) maxval = baseval + Math.Max(maxval, ++data[index]); else { baseval = maxval; data = new int[N]; } } for (int K = 0; K < N; K++) data[K] += baseval; return data; }
I think that's O(N+K)
. Depends on how you count the Order of re-initializing the array.
回答6:
Same principle as everybody scoring 100% really, it is just that I find this version easier to read (and it is probably only because I wrote it).
using System; using System.Linq; class Solution { public int[] solution(int N, int[] A) { var currentMax = 0; var resetValue = 0; var counters = Enumerable.Range(1, N).ToDictionary(i => i, i => 0); foreach (var a in A) { if (a == N + 1) resetValue = currentMax; else { counters[a] = Math.Max(counters[a], resetValue) + 1; currentMax = Math.Max(currentMax, counters[a]); } } return counters.Values.Select(v => Math.Max(v,resetValue)).ToArray(); } }
回答7:
public int[] counters(int N, int[] A) { int[] count = new int[N]; int maxCount = 0; int setAll = 0; for (int i = 0; i < A.Length; i++) { if (A[i] == N + 1) { setAll += maxCount; maxCount = 0; count = new int[N]; } else { count[A[i] - 1] += 1; if (count[A[i] - 1] > maxCount) { maxCount = count[A[i] - 1]; } } } for (int j = 0; j < count.Length; j++) { count[j] += setAll; } return count; }
I think this is O(N+K), but codility say its O(N*K)? Would appreciate if anyone could explain which is correct...
回答8:
A 100/100 solution in php
function solution($N, $A){ $cond = $N + 1; $cur_max = 0; $last_upd = 0; $cnt_arr = array(); $cnt = count($A); for($i = 0; $i < $cnt; $i++){ $cur = $A[$i]; if($cur == $cond){ $last_upd = $cur_max; } else{ $pos = $cur - 1; if(!isset($cnt_arr[$pos])){ $cnt_arr[$pos] = 0; } if($cnt_arr[$pos] < $last_upd){ $cnt_arr[$pos] = $last_upd + 1; } else{ $cnt_arr[$pos] ++; } if($cnt_arr[$pos] > $cur_max){ $cur_max = $cnt_arr[$pos]; } } } for($i = 0; $i < $N; $i++){ if(!isset($cnt_arr[$i])){ $cnt_arr[$i] = 0; } if($cnt_arr[$i] < $last_upd){ $cnt_arr[$i] = $last_upd; } } return $cnt_arr; }
回答9:
Rue, I just ran this locally. Watched the counters myself. I used this algorithm:
public int[] solution(int N, int[] A) { int[] result = new int[N]; int maximum = 0; int resetlimit = 0; for (int K = 0; K < A.Length; K++) { if (A[K] < 1 || A[K] > N + 1) { throw new InvalidOperationException(); } if (A[K] >= 1 && A[K] <= N) { if (result[A[K] - 1] < resetlimit) { result[A[K] - 1] = resetlimit + 1; } else { result[A[K] - 1]++; } if (result[A[K] - 1] > maximum) { maximum = result[A[K] - 1]; } } else { resetlimit = maximum; result = Enumerable.Repeat(maximum, result.Length).ToArray(); } } //for (int i = 0; i < result.Length; i++) //{ // result[i] = Math.Max(resetlimit, result[i]); //} return result; } }
looking at the problem and the result sets, you must include in the inefficient for loop in the else statement. The for loop outside does not replicate the 2nd operation
In order for iteration A[3] = 6 to set result[] all to '2' you must load the result array with the maximum counter. Otherwise your return will never have (2,2,2,2,2) as the 4th example array shows.
I too must take a test to get my dream job so the little inefficiency here is important;
the statement
result = Enumerable.Repeat(maximum, result.Length).ToArray();
loads the array all in one shot so no inner loop and no inner efficiency. I think that is pretty close to the correct result sets. I'm surprised they didn't ask to return like a jagged array of the total return. Still, this codility test scares me a lot.
回答10:
C++11 code:
#include <algorithm> vector<int> solution(int N, vector<int> &A) { vector<int> hist(N, 0); int last_update = 0; int max_value = 0; for (auto i : A){ if (1 <= i && i <= N){ int& val = hist[i - 1]; if (val < last_update) val = last_update + 1; else val++; if (max_value < val) max_value = val; } if (i == (N+1)){ last_update = max_value; } } replace_if(hist.begin(), hist.end(), [last_update](int x){return x < last_update;}, last_update); return hist; }
回答11:
The key is that [0] * N is an N operation. If that exists in a for loop it will become N*M. Tested in Codility 100%
# you can write to stdout for debugging purposes, e.g. # print "this is a debug message" def solution(N, A): # write your code in Python 2.7 count = [0] * N maxCounter = 0 minCounter = 0 for x in A: if x <= N and x >= 1: count[x-1] = max(count[x-1], minCounter) + 1 if maxCounter < count[x-1]: maxCounter = count[x-1] if x == N + 1: minCounter = maxCounter for i in xrange(N): count[i] = max(count[i], minValue) return count
回答12:
Here is Scala version, 100% on codility:
import java.util def solution(N: Int, A: Array[Int]): Array[Int] = { var counters = new Array[Int](N) var maxCounter = 0 for(ind <- 0 to A.length-1){ if(A(ind) == (N+1)){ //all to max util.Arrays.fill(counters,maxCounter) }else{ //ind -1 cause array index start with 0 which is marked as 1 in the input data counters(A(ind)-1) += 1 //update max counter if necessary if(maxCounter< (counters(A(ind)-1))) maxCounter = (counters(A(ind)-1)) } } return counters }
Performance: https://codility.com/demo/results/trainingKJT6Y3-74G/
回答13:
Ruby Codility Code that got 100/100
def solution(a) if a.length < 3 0 end a.sort! for i in 2..a.length - 1 if (a[i-2] + a[i-1]) > a[i] return 1 end end 0 end