Palindrome Partitions - python

Given a string split it into as few strings as possible such that each string is a palindrome
k = "racecarannakayak"
palin = [] # to get palindrome strs
i, j = 0, 2
while j != len(k) + 1:
if k[i:j] == k[:j][::-1]:
palin.append(k[i:j])
i += 1
j += 1
print(palin)
the result is ["racecar"] but it should be ["racecar", "anna", "kayak"]
what is wrong with my code??

There are a few issues with your code.
First, your pointer i keeps iterating even though your point j is
smaller than it in most of the iterations. Meaning you are doing
stuff like k[10:2] which will be pointless.
Second, your pointer j works only once over the whole array. Meaning
you either need multiple passes OR you need to reset the i pointer to
the last position of j pointer IF you find a palindrome.
Third, there is no condition to make sure that single alphabet string
is not considered a palindrome by your inversion logic
Last, there seems to be a typo, as mentioned by #fas in the comments. k[i:j]==k[i:j][::-1] instead of what you have written.
If you consider the above 3 and make the necessary changes you should get the right results to your code as below -
k = "racecarannakayak"
palin = [] # to get palindrome strs
i, j = 0, 2
while j != len(k) + 1:
if k[i:j] == k[i:j][::-1] and len(k[i:j])>2: #Check length is >2
palin.append(k[i:j])
i=j #Reset i pointer to current j
j += 1
print(palin)
['racecar', 'anna', 'kayak']

Related

to change value from 0 to 1 in a list of zeroes

n and k are user inputs, L is a list of zeroes.
if k is even, change the value to 1 of even indexes.
if k is odd, change the value to 1 of odd indexes.
but the output is just ones
['1','1','1','1']
can someone please guide me?
n=int(input())
k=int(input())
L=[0]*n
for i in range(len(L)):
if(k%2==0):
L[i]='1'
elif(k%2!=0):
L[i]='1'
print(L)
In your logic, whether the value is even or odd, you are doing the same process at both steps. You should consider whether the index is odd or even in your logic.
to do this, modify your if statements to incorporate the index:
for i in range(len(L)):
if(k % 2 == 0 and i % 2 == 0):
L[i]= 1
elif(k % 2 != 0 and i % 2 != 0):
L[i]= 1
This checks to ensure that not only the value you're concerned with is even or odd, but if their index value is as well.
You're current for loop modifies every item, you need to add a test to see if you';re looking at an odd or even item in the list:
n=int(input())
k=int(input())
L=[0]*n
for i in range(len(L)):
if k % 2 == 0 and i % 2 == 0:
L[i] = 1
elif k % 2 != 0 and i % 2 != 0:
L[i] = 1
print(L)
well any number should be either even or odd
and the user enter the value of k once
here you change the value to one in case the number is even
if(k%2==0):
L[i]='1'
here you change the value to one in case the number is odd
if(k%2!=0):
L[i]='1'
in either cases you change the value to one and accordingly the output is obvious to be ones => ['1','1','1', ...]
I am not sure what you want to do but I can see two problems
first: the value of k is constant across the whole loop (probably you should use i instead of k)
second: you may change L[i]='1' to L[i]='0' in any of the two conditions
Your current logic reads like this: If k is odd, set the item to 1; if it is even, do the same. You do not consider the even- or odd-ness of the index at all. Instead, compare the even-ness of k to that of the index i:
for i in range(len(L)):
if k % 2 == i % 2:
L[i] = '1'
Or, use range with (start, stop, step) parameters to only iterate the even or odd indices in the first place:
for i in range(k % 2, len(L), 2):
L[i] = '1'
Also, your original list has the int value 0, and you are replacing those with the str value '1'. You probably use int consistently, i.e. L[i] = 1
In this case, you can also use a list comprehension:
L = [int(i % 2 == k % 2) for i in range(n)]

Next Word in Lexicographic Order

Problem
There is a word given. We need to find the next word occurring in lexicographic order.For example, if word is lkjihfg then the next word would be lkjihgf.
This is a problem at Hackerrank that you can see here.
The problem for reference:
Complete the biggerIsGreater function in the editor below. It should
return the smallest lexicographically higher string possible from the
given string or no answer.
My effort
What i've tried was finding the maximum index(say indx) of word such that after it all the characters are non increasing.Then swapping the char at indx with the minimum char ahead that is greater than char at indx. Finally, reversing the string after indx.
Code
def biggerIsGreater(w):
ww = list(set(w))
indx = -1
l = [ord(ch)for ch in w]
for i in range(len(l)-1):
if l[i] < l[i+1]:
indx = i
else:
continue
if indx == -1:
return "no answer"
j = len(l) - 1
for x in range(j,indx,-1):
if l[x] > l[indx]:
l[x], l[indx] = l[indx], l[x]
break
l[indx+1 : ] = l[len(l) - 1 : indx : -1]
y = []
for z in l:
y.append(chr(z))
ans = ''.join(y)
return ans
The problem with this code is that it's not passing all the test cases because it's producing wrong results.
The good thing about your solution is that it has a good time complexity - O(n), where n is a size of the input string. That's why you don't have any timeout errors.
The problem with this code is, however is not all the test cases are validating.
That's so because you've missed one important case in your loop below:
for x in range(j,indx,-1):
if l[x] >= l[indx]:
l[x], l[indx] = l[indx], l[x]
break
Consider a case like 5 4 6 4. So, your indx is 2 and because of your condition l[x] >= l[indx] you will replace l[2] = 4 with l[0] = 4. This way, your next word in lexicographical order won't change and you'll get a wrong result 5 4 4 6 even though it must be 5 6 4 4.
So, if you make your condition stricter > and not >= because you actually need a LARGER character from the left then the solution will be working correctly.
Hence, just change your condition to > :
for x in range(j,indx,-1):
if l[x] > l[indx]: # fix the sign here
l[x], l[indx] = l[indx], l[x]
break
I tested your code with the fix and it passed all the tests.

Efficient permutations of array elements with no repetitions in python [duplicate]

So I received a challenge that states the following:
"Design a program that takes as input a 9 digit number where no digit appears twice and produces as output an arrangement of the same 9 digits corresponding to the next highest number. If no such number exists, the algorithm should indicate this. So for example, if the input is 781623954 the output would be 781624359."
So I came up with this idea to flip the indexes, so check the last index with the one right before to see which is bigger and compare then flip if necessary but for some reason my code isn't working. I only did the work for checking the last two digits not all the digits, so if you can help me out and check it for me and if you have any better ideas on how to tackle this problem, please share.
input = raw_input("Enter 9 Digits: ")
x = 9
while x>0:
x-=1
if input[8] > input[7]:
temp = input[8]
input[8] == input[7]
input[7] == temp
print input
break
Here's a more efficient approach, using the algorithm of the 14th century Indian mathematician Narayana Pandita, which can be found in the Wikipedia article on Permutation. This ancient algorithm is still one of the fastest known ways to generate permutations in order, and it is quite robust, in that it properly handles permutations that contain repeated elements.
The code below includes a simple test() function that generates all permutations of an ordered numeric string.
#! /usr/bin/env python
''' Find the next permutation in lexicographic order after a given permutation
This algorithm, due to Narayana Pandita, is from
https://en.wikipedia.org/wiki/Permutation#Generation_in_lexicographic_order
1. Find the largest index j such that a[j] < a[j + 1]. If no such index exists,
the permutation is the last permutation.
2. Find the largest index k greater than j such that a[j] < a[k].
3. Swap the value of a[j] with that of a[k].
4. Reverse the sequence from a[j + 1] up to and including the final element a[n].
Implemented in Python by PM 2Ring 2015.07.28
'''
import sys
def next_perm(a):
''' Advance permutation a to the next one in lexicographic order '''
n = len(a) - 1
#1. Find the largest index j such that a[j] < a[j + 1]
for j in range(n-1, -1, -1):
if a[j] < a[j + 1]:
break
else:
#This must be the last permutation
return False
#2. Find the largest index k greater than j such that a[j] < a[k]
v = a[j]
for k in range(n, j, -1):
if v < a[k]:
break
#3. Swap the value of a[j] with that of a[k].
a[j], a[k] = a[k], a[j]
#4. Reverse the tail of the sequence
a[j+1:] = a[j+1:][::-1]
return True
def test(n):
''' Print all permutations of an ordered numeric string (1-based) '''
a = [str(i) for i in range(1, n+1)]
i = 0
while True:
print('%2d: %s' % (i, ''.join(a)))
i += 1
if not next_perm(a):
break
def main():
s = sys.argv[1] if len(sys.argv) > 1 else '781623954'
a = list(s)
next_perm(a)
print('%s -> %s' % (s, ''.join(a)))
if __name__ == '__main__':
#test(4)
main()
I am not convinced that your approach of flipping digits is guaranteed to find the next highest number (at least not without further checks)
Here a simple solution:
Simply increment the input number and check if the conditions are met or if no number can be found.
set() can be used to get the set of unique digits in the number.
input_num = '781623954'
next_num = int(input_num) + 1
input_digits = set(input_num)
found = False
while not found:
next_num += 1
next_digits = set(str(next_num))
found = len(next_digits) == 9 and input_digits == next_digits
if next_num > 987654321:
break
if found:
print(next_num)
else:
print("No number was found.")
input[8] == input[7]
input[7] == temp
you probably meant:
input[8] = input[7]
input[7] = temp
didn't you?
Which, as stated in the comments, wouldn't work directly on the string, as it is immutable in Python. So, as a first step, you could make a list of characters from that string:
input = list(input)
and as a last step, get a string back from the modified list:
input = ''.join(input)
BTW, you might want to benefit from Python tuple unpacking which allows you to swap two variables without having to introduce a third one:
input[7], input[8] = input[8], input[7]

Alternate letters in a string - code not working

I am trying to make a string alternate between upper and lower case letters. My current code is this:
def skyline (str1):
result = ''
index = 0
for i in str1:
result += str1[index].upper() + str1[index + 1].lower()
index += 2
return result
When I run the above code I get an error saying String index out of range. How can I fix this?
One way using below with join + enumerate:
s = 'asdfghjkl'
''.join(v.upper() if i%2==0 else v.lower() for i, v in enumerate(s))
#'AsDfGhJkL'
This is the way I would rewrite your logic:
from itertools import islice, zip_longest
def skyline(str1):
result = ''
index = 0
for i, j in zip_longest(str1[::2], islice(str1, 1, None, 2), fillvalue=''):
result += i.upper() + j.lower()
return result
res = skyline('hello')
'HeLlO'
Explanation
Use itertools.zip_longest to iterate chunks of your string.
Use itertools.islice to extract every second character without building a separate string.
Now just iterate through your zipped iterable and append as before.
Try for i in range(len(str1)): and substitute index for i in the code. After, you could do
if i % 2 == 0: result += str1[i].upper()
else: result += str1[i].lower()
For every character in your input string, you are incrementing the index by 2. That's why you are going out of bounds.
Try using length of string for that purpose.
you do not check if your index is still in the size of your string.
It would be necessary to add a condition which verifies if the value of i is always smaller than the string and that i% 2 == 0 and that i == 0 to put the 1st character in Upper
with i% 2 == 0 we will apply the upper one letter on two
for i, __ in enumerate(str1):
if i+1 < len(str1) and i % 2 == 0 or i == 0:
result += str1[i].upper() + str1[i + 1].lower()
I tried to modify as minimal as possible in your code, so that you could understand properly. I just added a for loop with step 2 so that you wouldn't end up with index out of range. And for the final character in case of odd length string, I handled separately.
def skyline (str1):
result = ''
length = len(str1)
for index in range(0, length - 1, 2):
result += str1[index].upper() + str1[index + 1].lower()
if length % 2 == 1:
result += str1[length - 1].upper()
return result
You can use the following code:
def myfunc(str1):
result=''
for i in range(0,len(str1)):
if i % 2 == 0:
result += str1[i].upper()
else:
result += str1[i].lower()
return result
in your code you are get 2 word by one time so you should divide your loop by 2 because your loop work by depending your input string so make an variable like peak and equal it to len(your input input) then peak = int(peak/2) it will solve your pr
def func(name):
counter1 = 0
counter2 = 1
string = ''
peak = len(name)
peak = int(peak/2)
for letter in range(1,peak+1):
string += name[counter1].lower() + name[counter2].upper()
counter1 +=2
counter2 +=2
return string

Program terminated due to time out

PROBLEM :
You are given a list of size N, initialized with zeroes. You have to perform M operations on the list and output the maximum of final values of all the elements in the list. For every operation, you are given three integers a,b and k and you have to add value to all the elements ranging from index a to b(both inclusive).
Input Format
First line will contain two integers N and M separated by a single space.
Next lines will contain three integers a,b and k separated by a single space.
Numbers in list are numbered from 1 to N.
Here is the code which I have written:
n,m=map(int,input().split())
arr=[]
for i in range(n+1):
arr.append(0)
for j in range(m):
a,b,k=map(int,input().split())
for i in range(a,b+1):
arr[i]+=k;
print(max(arr))
When I try to submit my solution I get a "TERMINATED DUE TO TIMOUT" message.Could you please suggest a strategy to avoid these kind of errors and also a solution to the problem.
Thanks in advance!
Don't loop over the list range; instead, use map again to increment the indicated values. Something like
for j in range(m):
a,b,k=map(int,input().split())
arr[a:b+1] = map(lambda <increment-by-k>, arr[a:b+1])
This should let your resident optimization swoop in and save some time.
You probably need an algorithm that has better complexity than O(M*N).
You can put interval delimiters in a list:
n,m=map(int,input().split())
intervals = []
arr = [0 for i in range(n)]
for j in range(m):
a,b,k=map(int,input().split())
intervals += [(str(a), "begin", k)]
intervals += [(str(b), "end", k)]
intervals = sorted(intervals, key=lambda x: x[0]+x[1])
k, i = 0, 0
for op in intervals:
ind = int(op[0])
if op[1] == "begin":
while ind > i:
arr[i] += k
i += 1
k += op[2]
else:
while i <= ind:
arr[i] += k
i+= 1
k -= op[2]
print(arr)
If the sorting algorithm is O(MlogM), this is O(MlogM + N)

Categories