I basically want to put each letter to a different list so that the first letter goes in the first list until the kth letter. Then the k+1th letter should go in the k-1th list and the next to the k-2th list etc. The fact is that after the second loop the while enters in an infinite loop
def f(s,k):
l = [[] for i in range(k)]
i = 0
while i < len(s):
for j in range(0,k):
l[j].append(s[i])
print(l)
i += 1
for k in range(k-2,-1,-1):
l[k].append(s[i])
print(l)
i += 1
return l
Don't use the same variable k for the second iteration variable and your function parameter. When the second loop is done, k will be set to 0. The next iteration of the while loop will then do for j in range(0, 0):, which doesn't do anything, followed by for k in range(-2, -1, -1):, which also doesn't do anything. So i never gets incremented any more, and you get stuck in the infinite loop.
Change for k to for m and you won't get the infinite loop. But you'll get an IndexError when accessing s[i] if len(s) is not a multiple of 2 * k - 1.
It would be better to iterate over the characters in s.
def f(s,k):
l = [[] for i in range(k)]
i = 0
inc = 1
for c in s:
l[i].append(c)
i += inc
# Check if we need to reverse direction
if inc == 1 and i == k:
inc = -1
i = k - 2
elif inc == -1 and i == -1:
inc = 1
i = 0
return l
As #Barmar already stated, the reason why your algorithm does not work are the for-loops. So you effectively skip the first letter, at least.
Also the usage of k is problematic.
However his proposed algorithm doesn't work like you want it to work, though.
In the end this is what #Barmar had in mind:
def f(string, k):
result = [[] for _ in range(k)]
bin_index = -1
inc = 1
for i in range(len(string)):
bin_index += inc
# reverse by setting the bin_index and changing the increment-step
if bin_index == k:
bin_index = (k - 1) - 1
inc = -1
# going forward again
if bin_index == 0 and i != 0:
inc = 1
result[bin_index].append(string[i])
return result
#Barmar:
You have a bug in your program when i returns from the back-pass. It will not be set to another bin-index so that always the character on index k+1 and k+2 (or multiples of them) will be in the same bin (the first list). But they should be in two different bins. So this would get rid of the bug:
def f(s, k):
l = [[] for i in range(k)]
i = 0
inc = 1
for c in s:
l[i].append(c)
i += inc
# Check if we need to reverse direction
if inc == 1 and i == k:
inc = -1
i = k - 2
elif inc == -1 and i == -1:
inc = 1
i = 1 # this should be 1 not 0
return l
Related
I wrote the following code. It should return to me the length of the longest subscript in a string without a repeat in letters.
def lengthOfLongestSubstring(s):
lst = []
y = 0
final = 0
count = len(s)
while len(s) > 0:
s = s[y:]
for i in range(len(s)):
if s[i] in lst:
y += 1
count = len(lst)
lst =[]
break
else:
lst.append(s[i])
if count > final:
final=count
return(final)
when entering the string "tmmzuxt" i expect to get an output of 5 (length of "mzuxt") but instead get 4. I have debugged to figure out the problem seems to be that my function skips over the second 'm' when indexing but I can't figure out why. Any suggestions?
Realized I somehow missed a line. Hope this makes more sense.
Your issue here is that you are modifying s while you are running your code.
Consider that in the first iteration, you are getting s = s[0:], so s will now be 'tmmzuxt'. In your next iteration, you are getting s = s[1:], from the modified s. This is still not a problem, because you just get 'mmzuxt'. However, in your third iteration, you are getting s = s[2:], which is now 'zuxt'.
So you need a different variable than s to hold the substring of s that you are actually testing.
here, in your code(line 7) you are updating your string value inside function, everytime your for loop iterates.
for e.g., after every break inside for loop. you string(which is "tmmzuxt") is becoming short and short.
i created a new variable which contains your original string.
def lengthOfLongestSubstring(s):
lst = []
y = 0
final = 0
count = len(s)
main_string = s;#change done here
while len(s) > 0:
s = main_string[y:] #change done here
for i in range(len(s)):
if s[i] in lst:
y += 1
count = len(lst)
lst =[]
break
else:
lst.append(s[i])
if count > final:
final =count
print(final)
return(final)
lengthOfLongestSubstring("tmmzuxt")
The main problem with your code is that you incremented y, even though it should only ever remove the first character. There is no need for a variable y. Try this:
def lengthOfLongestSubstring(s):
final = 0
while len(s) > 0:
count = len(s)
lst = []
for i in range(len(s)):
if s[i] in lst:
count = i - 1
break
lst.append(s[i])
if count > final:
final = count
s = s[1:]
return final
print(lengthOfLongestSubstring("tmmzuxt"))
Here is an edited code. removing #lst =[] and #break lines.
[Code]
def lengthOfLongestSubstring(s):
lst = []
y = 0
final = 0
count = len(s)
while len(s) > 0:
s = s[y:]
for i in range(len(s)):
if s[i] in lst:
y += 1
count = len(lst)
#lst =[]
#break
else:
lst.append(s[i])
if count > final:
final=count
return(final)
s="tmmzuxt"
print(lengthOfLongestSubstring(s))
[Output]
5
I'm not sure if I understand your code, or if the while loop is needed here, actually. Try this instead:
def lengthOfLongestSubstring(s):
max_length = 0
length = 0
previous = ''
for thisCharacter in s:
if thisCharacter != previous:
length += 1
else:
max_length = max(length, max_length)
length = 1
return max_length
I have the following code with the only difference being the j and the I position in my list. Is there any way to make it better by writing a function or something like that because I can't quite figure it out?
for i in range(dimension):
for j in range(dimension - 4):
k = 1
while k < 5 and gameboard[i][j+k] == gameboard[i][j]:
k += 1
if k == 5:
winner = gameboard[i][j]
for i in range(dimension):
for j in range(dimension - 4):
k = 1
while k < 5 and gameboard[j+k][i] == gameboard[j][i]:
k += 1
if k == 5:
winner = gameboard[j][i]
You could merge the two loops by inserting an additional nested loop that handles the permutations of i and j and the corresponding dimension deltas:
for i in range(dimension):
for j in range(dimension - 4):
for i,j,di,dj in [ (i,j,0,1), (j,i,1,0) ]:
k = 1
while k < 5 and gameboard[i+k*di][j+k*dj] == gameboard[i][j]:
k += 1
if k == 5:
winner = gameboard[i][j]
Generalized for all directions
Alternatively you could create a function that tells you if there is a win in a given direction and use that in a loop.
def directionWinner(board,i,j,di,dj):
player,pi,pj = board[i][j],i,j
# if player == empty: return
for _ in range(4):
pi,pj = pi+di, pj+dj
if pi not in range(len(board)): return
if pj not in range(len(board)): return
if board[pi][pj] != player: return
return player
Then use it to check all directions:
for pos in range(dimensions*dimensions):
i,j = divmod(pos,dimensions)
for direction in [ (0,1),(1,0),(1,1),(1,-1) ]:
winner = directionWinner(gameboard,i,j,*direction)
if winner is not None: break
else: continue; break
The directions are represented by the increase/decrease in vertical and horizontal coordinates (deltas) for each step of one. So [ (0,1),(1,0),(1,1),(1,-1) ] gives you "down", "across", "diagonal 1", diagonal 2" respectively.
Checking only from last move
The same idea can be used to check for a winner from a specific position (e.g. checking if last move is a win):
# count how may consecutive in a given direction (and its inverse)
def countDir(board,i,j,di,dj,inverted=False):
player,pi,pj = board[i][j],i,j
count = 0
while pi in range(len(board) and pj in range(len(board)):
if board[pi][pj] == player: count += 1
else: break
pi, pj = pi+di, pj+dj
if not inverted:
count += countDir(board,i,j,-di,-dj,True)-1
return count
def winnerAt(board,i,j):
for direction in [ (0,1),(1,0),(1,1),(1,-1) ]:
if countDir(board,i,j,*direction)>=5:
return board[i,j]
Then, after playing at position i,j, you can immediately know if the move won the game:
if winnerAt(gameboard,i,j) is not None:
print(gameboard[i][j],"wins !!!")
It's maybe a trivial change, but why don't you just put the second check in the first loop just by swapping indices and using another variable for the while part? I mean something like this:
def check_winner(gameboard, dimension):
for i in range(dimension):
for j in range(dimension - 4):
# perform the first check
k = 1
while k < 5 and gameboard[i][j+k] == gameboard[i][j]:
k += 1
if k == 5:
return gameboard[i][j]
# and the second check
l = 1
while l < 5 and gameboard[j + k][i] == gameboard[j][i]:
l += 1
if l == 5:
return gameboard[j][i]
Anyways, it's cleaner to just return if you found the winner, and avoid redundancy.
I need to write a function to find the smallest window that contains all the elements in an array. Below is what I have tried:
def function(item):
x = len(set(item))
i = 0
j = len(item) - 1
result = len(item)
while i <= j:
if len(set(item[i + 1: j + 1])) == x:
result = min(result, len(item[i + 1: j + 1]))
i += 1
elif len(set(item[i:j])) == x:
result = min(result, len(item[i:j]))
j -= 1
else:
return result
return result
print(function([8,8,8,8,1,2,5,7,8,8,8,8]))
The time complexity is in O(N^2), Can someone help me to improve it to O(N) or better? Thanks.
You can use the idea from How to find smallest substring which contains all characters from a given string? for this specific case and get a O(N) solution.
Keep a counter for how many copies of each unique number is included in the window and move the end of the window to the right until all unique numbers are included at least once. Then move the start of the window until one unique number disappears. Then repeat:
from collections import Counter
def smallest_window(items):
element_counts = Counter()
n_unique = len(set(items))
characters_included = 0
start_enumerator = enumerate(items)
min_window = len(items)
for end, element in enumerate(items):
element_counts[element] += 1
if element_counts[element] == 1:
characters_included += 1
while characters_included == n_unique:
start, removed_element = next(start_enumerator)
min_window = min(end-start+1, min_window)
element_counts[removed_element] -= 1
if element_counts[removed_element] == 0:
characters_included -= 1
return min_window
>>> smallest_window([8,8,8,8,1,2,5,7,8,8,8,8])
5
This problem can be solved as below.
def lengthOfLongestSublist(s):
result = 0
#set a dictionary to store item in s as the key and index as value
d={}
i=0
j=0
while (j < len(s)):
#if find the s[j] value is already exist in the dictionary,
#move the window start point from i to i+1
if (s[j] in d):
i = max(d[s[j]] + 1,i)
#each time loop, compare the current length of s to the previouse one
result = max(result,j-i+1)
#store s[j] as key and the index of s[j] as value
d[s[j]] = j
j = j + 1
return result
lengthOfLongestSubstring([8,8,8,8,8,5,6,7,8,8,8,8,])
Output: 4
Set a dictionary to store the value of input list as key and index
of the list as the value. dic[l[j]]=j
In the loop, find if the current value exists in the dictionary. If
exist, move the start point from i to i + 1.
Update result.
The complexity is O(n).
I am writing a function to find all the hills and valleys in a given list. For instance, [1,0,0,0,1] returns 3 and [0,1,0,1,0] returns 5. [0,2,2,1,1,0,0] returns 3. If a number (or consecutive numbers with same values) are bigger or smaller than both of its neighbors, it is considered as a hill or a valley.
Below is my code:
def hill_and_vally(s):
if not s or len(s) < 2:
return 0
i = 0
count = 0
pre = None
while i < len(s):
if i == 0:
while s[i] == s[i+1]: # loop until value is different
i += 1
i += 1
if i < len(s): # check if it reaches the end
count += 1
pre = s[i-1] # track the previous value
elif i == len(s) - 1:
while s[i] == s[i-1]:
i -= 1
i -= 1
if i >= 0:
count += 1
break
else:
while s[i] == s[i+1]:
i += 1
i += 1
if s[i] > s[i-1] and pre > s[i-1]: # it is a valley
count += 1
elif s[i] < s[i-1] and pre < s[i-1]: # it is a hill
count += 1
pre = s[i-1]
return count
Can someone help me to improve the complexity to O(N). Or show me another way to do it with better complexity? Please show me some examples. Thanks in advance.
Here's how I would do it:
compute differences d between consecutive elements (remove 0s from result)
count the number of times the sign changes in d
return 2 plus that count (because there is a hill and a valley even in a monotonically increasing sequence)
In code:
def hill_and_vally(s):
d=[x1-x0 for x0,x1 in zip(s,s[1:]) if x1!=x0]
return 2+sum(d0*d1<0 for d0,d1 in zip(d,d[1:]))
of course it can be implemented with for loops and indexes, but zip and list comprehensions is more pythonic.
zip(s,s[1:]) is a common way to get pairs of adjacent elements in a list.
Tests:
>>> hill_and_vally([1,0,0,0,1])
3
>>> hill_and_vally([0,1,0,1,0])
5
>>> hill_and_vally([0,2,2,1,1,0,0])
3
Handling corner cases such as the reported [1,1,1,1] is left as an exercise :-)
I know that the question is quite old and already answered, but recently solved the same problem with just one linear scan:
def solution(arr):
prev = None
curr = None
total = 0
for n in arr:
if curr == None:
curr = n
else:
if n != curr:
if prev != None:
if (prev < curr and n < curr) or (prev > curr and n > curr):
total += 1
else:
prev = curr
total += 1
prev = curr
curr = n
if prev != curr:
total += 1
return total
It works well for all the inputs:
print(solution([1])) # 1
print(solution([1,2])) # 2
print(solution([1,1,1])) # 1
print(solution([1,2,1])) # 3
print(solution([1,2,6])) # 2
print(solution([1,2,3,4,4,3,4,4,5,6])) # 4
print(solution([-10,2,2,2,2])) # 2
print(solution([1,0,0,0,1])) # 3
print(solution([0,1,0,1,0])) # 5
print(solution([0,2,2,1,1,0,0])) # 3
What it does, it keeps track of previous downhill/uphill and increments total counter if another appropriate downhill/uphill is met.
I have tried to implement the brute force approach to solving a Sudoku puzzle using Python, as explained in the following link: http://en.wikipedia.org/wiki/Sudoku_solving_algorithms#Brute-force_algorithm
I am aware there are other threads with the same question. I have read through all of them and still keep having problems.
Here is my code for recursion:
def recurse(x, k, grid):
if x > 8:
for line in grid:
print line
raw_input()
if grid[x][k] == '0':
for number in '123456789':
if clear(number, x, k, grid):
grid[x] = grid[x][0:k] + number + grid[x][k+1:]
k += 1
if k > 8:
x += 1
k = 0
recurse(x, k, grid)
k -= 1
if k < 0:
x -= 1
k = 8
else:
k += 1
if k > 8:
x += 1
k = 0
recurse(x, k, grid)
Basically I keep the Sudoku in an array of 9x9 slots, where grid[x] accesses the xth line of the entire Sudoku and grid[x][k] accesses the kth number at the xth line.
There is a function up there called 'clear' which finds out whether a certain number can fit in that slot or not. I have tested it many times and it works properly. Problem here is that the value 'x' never goes above 8, which means the Sudoku never reaches the end. The recursion stops before all the slots are filled in correctly. I am quite inexperienced in writing recursive methods so please bear with me.
I figured, if a number fits in a slot, then that number is placed within that slot and then k is incremented. If k is above 8, then it means it is end of the line so we skip to the next line. Then the recurse function is called again. If a recurse function ends without being able to call itself again, then this means no number fits in that slot so we have to go back. In that case, k is decremented.
So what is the problem here exactly?
You forgot to reset the cells before backtracking. You're leaving wrong numbers all over the place, and at some point there is no valid number to fill in any more, and execution stops.
Add grid[x] = grid[x][0:k] + '0' + grid[x][k+1:] after
k -= 1
if k < 0:
x -= 1
k = 8
to fix this.
To stop recursing when a solution has been found:
def recurse(x, k, grid):
if x>8:
return grid
if grid[x][k] == '0':
for number in '123456789':
if clear(number, x, k, grid):
grid[x] = grid[x][0:k] + number + grid[x][k+1:]
k += 1
if k > 8:
x += 1
k = 0
solution= recurse(x, k, grid)
if solution:
return solution
k -= 1
if k < 0:
x -= 1
k = 8
grid[x] = grid[x][0:k] + '0' + grid[x][k+1:]
else:
k += 1
if k > 8:
x += 1
k = 0
return recurse(x, k, grid)