|
Edit: I originally asked about the performance of my code to go along with the topic, but it seems it doesn't even fully work for all cases. I'll leave the topic, since it still stands as something worthwhile. My code is listed below where others have commented on it. Peter's answer is long, and maybe hard to understand, but it goes through the rows and columns at the same time. I'm assuming that makes it faster and more efficient, since it loops through rows and columns separately. It would be great if someone was willing to benchmark all the code posted by everyone so far to see whose was most efficient. |
|
All of the code examples I've looked at so far seem to be running in time O(n^3), or in a few cases O(n^3 log n). It's not always obvious since Python can wrap a lot of processing into one line of code. Has anyone come up with an algorithm that does better than O(n^3)? EDIT: Now that I think about it, I see that it can be done in only O(n^2 log n). A nice example of this is the beautiful one-line procedure by @EnTerr. It starts by appending the original Sudoku square (a list of row-lists) with its transpose (a list of column-lists), so there are 2n lists of n elements each. This bit of overhead should take O(n^2) operations, I think. Then each of these 2n lists is sorted (which should take O(n log n) steps) and then compared to the range 1,...,n (which will take O(n) steps). Altogether that's O(n^2) + 2n * [O(n log n) + O(n)]. The dominant term there is 2n*O(n log n), or in other words O(n^2 log n). Actually, I wouldn't be surprised if creating the transposed was an O(1) operation. (I think Two nested loops so O(n^2) but I don't know about the complexity of append. Any ideas? Anything else expensive going on in there? def check_sudoku(square):
n=len(square)
if n==0:
return False
colnum=0
for e in square: # n elements
if len(e) != n:
return False
checker=1
rownum=0
col=[]
for nums in square: # n elements
col.append(square[rownum][colnum]) # complexity?
rownum+=1
colnum+=1
for nums in square: # n elements
if checker not in e or checker not in col: # I think this is probably O(1) - hash table?
return False
checker+=1
return True@fnenu: I had a little bit of trouble understanding your code at first because of the two "for nums in square" loops, since you don't actually use nums anywhere. You'd be better off doing something like "for rownum in range(n)" and "for checker in range(1, n+1)". But that shouldn't affect the overall complexity of your code. I'd assume that append() is an O(1) operation. However, I don't think checking membership in a list is O(1). I don't know anything about how Python implements lists internally but it seems unlikely that it would use hash tables for this. However, you raise a good point--you could rewrite this to use a dict instead of a list to store the rows and columns, and then the membership check could be done in O(1). I haven't thought it through carefully yet, but it seems like this would bring your algorithm down to O(n^2). range(n) wasn't taught in the course up to that point so I worked around it. I prefer to work within the bounds of the course instead of using other things in what I submit. I guess I should have tidied it up before posting. I tried to find some info on 'in' but couldn't work out what to look for to find its complexity. Doesn't look like it is O(1) though as you say. Edit: http://wiki.python.org/moin/TimeComplexity so it's O(n). |
Does your code work? It looks like it fails on cases such as
and
My code, which is what fnenu is referring to: