This code works fine for all the strings, except for the ones where the last char is needed.
s='abcdefghijklmnopqrstuvwxyz'
sub =''
test =s[0]
for n in range(len(s)-1):
if len(test) > len(sub):
sub = test
if s[n] >= s[n-1]:
test += s[n]
else:
test = s[n]
print 'Longest substring in alphabetic order is: ' + str(sub)
How do you suggest a possibility for doing this?
Thank you in advance guys!
PS:
Thanks for the answers so far. The problem is that, no matter which range I type, the sub variable, which I will print, doesn't get all the chars I want. The loop finishes before :\ Maybe it's a problem with the program itself.
Any extra tips? :)
Your problem is with range(len(s)-1). Range generates a list up to its upper limit parameter value-1 so you don't need to subtract1 to len(s), use:
range(len(s))
From https://docs.python.org/2/library/functions.html#range
range(stop)
range(start, stop[, step])
This is a versatile function to create lists containing arithmetic progressions. It is most often used in for loops. The arguments must
be plain integers. If the step argument is omitted, it defaults to 1.
If the start argument is omitted, it defaults to 0. The full form
returns a list of plain integers [start, start + step, start + 2 *
step, ...]. If step is positive, the last element is the largest start
+ i * step less than stop; if step is negative, the last element is the smallest start + i * step greater than stop. step must not be zero
On the other hand, you are labeling your question as python2.7 so I assume you are using 2.7. If that is the case, it is more efficient to use xrange instead range because that way you will use an iterator instead generating a list.
EDIT
From the comments to this question, you can change your code to:
s='caabcdab'
sub =''
test =s[0]
for i in range(1,len(s)+1):
n = i%len(s)
if len(test) > len(sub):
sub = test
if i >= len(s):
break
if s[n] >= s[n-1]:
test += s[n]
else:
test = s[n]
print 'Logest substring in alphabetic order is: ' + str(sub)
you enemurate instead of range:
s='abcdefghijklmnopqrstuvwxyz'
sub =''
test =s[0]
for n,value in enumerate(s):
if len(test) > len(sub):
sub = test
if value >= s[n-1]:
test += s[n]
else:
test = s[n]
You could do use the following code:
s = 'abcdefgahijkblmnopqrstcuvwxyz'
sub = ''
test = s[0]
for index, character in enumerate(s):
if index > 0:
if character > s[index - 1]:
test += character
else:
test = character
if len(test) > len(sub):
sub = test
print 'Longest substring in alphabetic order is: ' + str(sub)
A few pointers too.
Python strings are iterable. i.e you can loop through them.
Use enumerate when you want the index of the list while iterating it.
Related
Need to write a program that prints the longest substring of variable, in which the letters occur in alphabetical order.
eg. s = 'onsjdfjqiwkvftwfbx', it should returns 'dfjq'.
as a beginner, code written as below:
y=()
z=()
for i in range(len(s)-1):
letter=s[i]
while s[i]<=s[i+1]:
letter+=s[i+1]
i+=1
y=y+(letter,)
z=z+(len(letter),)
print(y[z.index(max(z))])
However, above code will always return
IndexError: string index out of range.
It will produce the desired result until I change it to range(len(s)-3).
Would like to seek advice on:
Why range(len(s)-1) will lead to such error message? In order to take care of index up to i+1, I have already reduce the range value by 1.
my rationale is, if the length of variable s is 14, it has index from 0-13, range(14) produce value 0-13. However as my code involves i+1 index, range is reduced by 1 to take care of this part.
How to amend above code to produce correct result.
if s = 'abcdefghijklmnopqrstuvwxyz', above code with range(len(s)-3) returns IndexError: string index out of range again. Why? what's wrong with this code?
Any help is appreciated~
Te reason for the out of range index is that in your internal while loop, you are advancing i without checking for its range. Your code is also very inefficient, as you have nested loops, and you are doing a lot of relatively expensive string concatenation. A linear time algorithm without concatenations would look something like this:
s = 'onsjdfjqiwkvftwfbcdefgxa'
# Start by assuming the longest substring is the first letter
longest_end = 0
longest_length = 1
length = 1
for i in range(1, len(s)):
if s[i] > s[i - 1]:
# If current character higher in order than previous increment current length
length += 1
if length > longest_length:
# If current length, longer than previous maximum, remember position
longest_end = i + 1
longest_length = length
else:
# If not increasing order, reset current length
length = 1
print(s[longest_end - longest_length:longest_end])
Regarding "1":
Actually, using range(len(s)-2) should also work.
The reason range(len(s)-1) breaks:
For 'onsjdfjqiwkvftwfbx', the len() will be equal to 18. Still, the max index you can refer is 17 (since indexing starts at 0).
Thus, when you loop through "i"'s, at some point, i will increase to 17 (which corresponds to len(s)-1) and then try access s[i+1] in your while comparison (which is impossible).
Regarding "2":
The following should work:
current_output = ''
biggest_output = ''
for letter in s:
if current_output == '':
current_output += letter
else:
if current_output[-1]<=letter:
current_output += letter
else:
if len(current_output) > len(biggest_output):
biggest_output = current_output
current_output = letter
if len(current_output) > len(biggest_output):
biggest_output = current_output
print(biggest_output)
This is the problem definition:
Given a string of lowercase letters, determine the index of the
character whose removal will make a palindrome. If is already a
palindrome or no such character exists, then print -1. There will always
be a valid solution, and any correct answer is acceptable. For
example, if "bcbc", we can either remove 'b' at index or 'c' at index.
I tried this code:
# !/bin/python
import sys
def palindromeIndex(s):
# Complete this function
length = len(s)
index = 0
while index != length:
string = list(s)
del string[index]
if string == list(reversed(string)):
return index
index += 1
return -1
q = int(raw_input().strip())
for a0 in xrange(q):
s = raw_input().strip()
result = palindromeIndex(s)
print(result)
This code works for the smaller values. But taken hell lot of time for the larger inputs.
Here is the sample: Link to sample
the above one is the bigger sample which is to be decoded. But at the solution must run for the following input:
Input (stdin)
3
aaab
baa
aaa
Expected Output
3
0
-1
How to optimize the solution?
Here is a code that is optimized for the very task
def palindrome_index(s):
# Complete this function
rev = s[::-1]
if rev == s:
return -1
for i, (a, b) in enumerate(zip(s, rev)):
if a != b:
candidate = s[:i] + s[i + 1:]
if candidate == candidate[::-1]:
return i
else:
return len(s) - i - 1
First we calculate the reverse of the string. If rev equals the original, it was a palindrome to begin with. Then we iterate the characters at the both ends, keeping tab on the index as well:
for i, (a, b) in enumerate(zip(s, rev)):
a will hold the current character from the beginning of the string and b from the end. i will hold the index from the beginning of the string. If at any point a != b then it means that either a or b must be removed. Since there is always a solution, and it is always one character, we test if the removal of a results in a palindrome. If it does, we return the index of a, which is i. If it doesn't, then by necessity, the removal of b must result in a palindrome, therefore we return its index, counting from the end.
There is no need to convert the string to a list, as you can compare strings. This will remove a computation that is called a lot thus speeding up the process. To reverse a string, all you need to do is used slicing:
>>> s = "abcdef"
>>> s[::-1]
'fedcba'
So using this, you can re-write your function to:
def palindromeIndex(s):
if s == s[::-1]:
return -1
for i in range(len(s)):
c = s[:i] + s[i+1:]
if c == c[::-1]:
return i
return -1
and the tests from your question:
>>> palindromeIndex("aaab")
3
>>> palindromeIndex("baa")
0
>>> palindromeIndex("aaa")
-1
and for the first one in the link that you gave, the result was:
16722
which computed in about 900ms compared to your original function which took 17000ms but still gave the same result. So it is clear that this function is a drastic improvement. :)
I want to compare following chars in a string and if they're equal, raise the counter.
With my example code I always get TypErrors related to line 6.
Do you know where's the problem?
Thank you!
def func(text):
counter = 0
text_l = text.lower()
for i in text_l:
if text_l[i+1] == text_l[i]:
print(text_l[i+1], text_l[i])
counter += 1
return counter
i is not an index. Your for will iterate over the elements directly, so i at any point of time is a character, not an integer. Use the range function if you want the indices:
for i in range(len(text_l) - 1): # i is the current index
if text_l[i + 1] == text_l[i]:
You can also use enumerate:
for i, c in enumerate(text_l[:-1]): # i is the current index, c is the current char
if text_l[i + 1] == c:
In either case, you'll want to iterate until the penultimate character because, you'll hit an IndexError on the last iteration with i + 1 as i + 1 is out of bounds for the last character.
I am trying to find the index of the first letter of a sub string within the main string. The function acts exactly like the find method of python. I have created a find_chr function that gives me the index of a character in a string and I am using the find_chr to get the index of the substring.
def find_str(s,x):
i=0
if x in s:
return find_chr(s,x[i])
else:
return -1
My problem is that when I am using the string "IS GOING GOING" and substring as "ING", I am getting the index of the first "I", when I am expecting the index of the "I" of "ING". I will appreciate any input about changing the function to get the right index of the first letter of the substring.
In find_str you call find_chr(s,x[i]). This is calling find_chr with only x[i] (the ith part of the substring).
This should fix your problem
def find_chr(s,char):
i=0
step = len(char)
for j in range(len(s)+1):
ch = s[j:j+step]
if ch==char:
return (i)
break
i+=1
return -1
def find_str(s,x):
i=0
if x in s:
return find_chr(s,x)
else:
return -1
You aren't looping through the characters, you only check for i == 0 (i.e. the first character in s). You need to apply a "window" to the string, checking len(s) characters in a row:
def find_str(s, x):
if x in s: # is x present?
for i in range(len(s)): # work through string indices
if s[i:i+len(x)] == x: # does x start at current index?
return i
return -1
This should solve your problem:
def find_str(s, x):
i = 0
while i < len(s):
if s[i:i + len(x)] == x:
return i
else:
i += 1
print find_str('IS GOING GOING', 'ING')
Look up the use of the index function in strings. You will then happily replace all of that code with about 1 line.
Supplying the answer because of the following comments. Seriously though, if one is going to learn python, it is a good exercise to be aware of the methods available for an object.
>>> 'is going going'.index('ing')
5
or more generally
>>> fullstring.index(substring)
This should be marked as the correct answer because it is the simplest and most obviously correct. The complexity of the algorithms offered is way too high for this problem.
If the substring is not in the fullstring, a ValueError exception will be raised. So if you need a function, then it should return the index from a try or -1 (or None) from the except blocks.
I am trying to get a simple function which takes n and prints
If n > 0:
print((n*'*')+(n*'!'), end=' ')
and trying to get the same solution but recursively. I am a beginner to recursion, and often I get the "higher level of thinking", but I am having trouble understanding the code that must follow.
My base case is that when n is 0 it prints nothing. When n is more than 1 it will print n copies of * + n copies of!
def repeat(n):
if n <= 0:
pass
else:
repeat(n-1)
print((n*'*')+(n*'!'), end=' ')
right now it prints n, and then n-1 successively until 0. I have tried breaking it up into two print statements and using more than one recursion .. but it becomes a messy pattern.
I am also not allowed to use loops. This one is driving me insane; I have come up with several solutions to it besides the easy one line statement, but none that use recursion.
It's simpler if you build and return a string and print it outside of the function, like this:
def printPattern(n):
if n <= 0:
return ''
return '*' + printPattern(n-1) + '!'
Or as a one-liner:
def printPattern(n):
return '*' + printPattern(n-1) + '!' if n > 0 else ''
Either way, this works:
print printPattern(5)
> *****!!!!!
Assume you have a solution for n - 1. Prepend * and append !.
def repeat(n):
if n > 0:
print("*", end=" ")
repeat(n - 1)
print("!", end=" ")
The following does what you appear to want.
def repeat(n):
def stars(n):
return '*'+stars(n-1)+'!' if n > 0 else ''
print stars(n)
For example, repeat(5) prints *****!!!!! and repeat(8) prints
********!!!!!!!!.
I don't actually know what you're asking... If there's a more efficient or better way of doing this? This would be quite obvious:
def repeat(n):
if n >= 0:
print((n*'*')+(n*'!'), end=' ')
return repeat(n-1)
I would use two strings here, and return a concatenated string of those two strings when n<=0 and use return instead of printing inside function:
def repeat(n, strs1="", strs2=""): # The Default value of strings is ""
if n <= 0:
return strs1 + strs2 # if n<=0 then concatenate the two strings and return them
else:
strs1 += "*" # Add * to strs1
strs2 += "!" # Add ! to strs2
return repeat(n-1, strs1, strs2) # Pass n-1, as well as the two strings to a recursive call
print(repeat(5))
print(repeat(3))
Output:
*****!!!!!
***!!!