Largest Palindrome Product of 2 3 digit numbers - python

Problem statement:
A palindromic number reads the same both ways. The largest palindrome made from the product of two 2-digit numbers is 9009 = 91 × 99.
Find the largest palindrome made from the product of two 3-digit numbers.
Here is what I've done.
for x in range(999,100,-1):
for y in range(x,100,-1):
check = str(x*y)
check_length = len(check)
if check_length % 2 == 0:
if check[0:check_length//2] == check[check_length:check_length//2:-1]:
print(check)
break
So I've cut out all repeat products (i.e. 999x998=998x999), convert it into a string and check if the two halves are the same after reversing the second string. This produces no result whatsoever. I am not looking for an answer but a hint as to the direction and also the pointing out any problems with the code. Thanks!
EDIT
for x in range(999,100,-1):
for y in range(x,100,-1):
check = str(x*y)
check_length = len(check)
if check[0:check_length//2] == check[check_length:check_length//2:-1]:
print(check)
break
Sample Output of check
580085
906609
119911
282282
853358
EDIT
Here is my final version which does the trick. Thanks for all the input.
largest_palindrome = 0
for x in range(999,100,-1):
for y in range(x,100,-1):
product = x*y
check = str(x*y)
if check == check[::-1]:
if product > largest_palindrome:
largest_palindrome = product
print(largest_palindrome)

Your check is wrong. Let’s take a look at an example:
>>> check = '123321'
>>> check_length = len(check)
>>> check[0:check_length//2]
'123'
>>> check[check_length:check_length//2:-1]
'12'
As you can see, you’re chopping off one character. That’s because you are splitting the string as check[6:3:-1] which keeps the index 3 out (because ranges are exclusive of the end). So correct would be the following:
>>> check[check_length:check_length//2 - 1:-1]
'123'
But you actually don’t need that complexity. There is no need to split the string in half and compare the halves. A palindrome is a string that reads forwards the same as backwards. So just compare the whole string with the whole string reversed:
>>> check
'123321'
>>> check[::-1]
'123321'
>>> check == check[::-1]
True
This also makes is easy to check one case which you didn’t account at all for: Uneven string lengths. A number 12321 is a palindrome too but because the string length is 5, you are completely ignoring it.
Finally there are two further issues with your code:
break from within the inner loop will not break the outer loop. So you will stop iterating y but the next iteration for x will start, so you are continuing the search for a while. You need a way to break the outer loop in that case too.
You are not looking for the largest palindrome. You are simply starting at the largest argument x and then check all possible y that make palindromes. But that will give you for example 998 * 583 as the largest palindrome, but there are easily numbers (with lower x) that will produce larger palindromes. So you should check all the palindromes you find, or iterate in another way.

def reverse(n):
Number = n
Reverse = 0
while(Number > 0):
Reminder = Number %10
Reverse = (Reverse *10) + Reminder
Number = Number //10
return Reverse
def multiple(i, j):
return i * j
def checkPalindrone(n, rn):
if (n == rn):
return True
else:
return False
def maxPalindrone():
mult = 0
returnPalidrone = []
for i in range(100,1000):
for j in range(100,1000):
mult = multiple(i,j)
if (checkPalindrone(mult, reverse(mult))):
returnPalidrone.append(mult)
else:
continue
return max(returnPalidrone)

Related

How do make a function that verifies if a piece of string is the mirror of another using a for loop? [duplicate]

I'm trying to check for a palindrome with Python. The code I have is very for-loop intensive.
And it seems to me the biggest mistake people do when going from C to Python is trying to implement C logic using Python, which makes things run slowly, and it's just not making the most of the language.
I see on this website. Search for "C-style for", that Python doesn't have C-style for loops. Might be outdated, but I interpret it to mean Python has its own methods for this.
I've tried looking around, I can't find much up to date (Python 3) advice for this. How can I solve a palindrome challenge in Python, without using the for loop?
I've done this in C in class, but I want to do it in Python, on a personal basis. The problem is from the Euler Project, great site By the way,.
def isPalindrome(n):
lst = [int(n) for n in str(n)]
l=len(lst)
if l==0 || l==1:
return True
elif len(lst)%2==0:
for k in range (l)
#####
else:
while (k<=((l-1)/2)):
if (list[]):
#####
for i in range (999, 100, -1):
for j in range (999,100, -1):
if isPalindrome(i*j):
print(i*j)
break
I'm missing a lot of code here. The five hashes are just reminders for myself.
Concrete questions:
In C, I would make a for loop comparing index 0 to index max, and then index 0+1 with max-1, until something something. How to best do this in Python?
My for loop (in in range (999, 100, -1), is this a bad way to do it in Python?
Does anybody have any good advice, or good websites, or resources for people in my position? I'm not a programmer, I don't aspire to be one, I just want to learn enough so that when I write my bachelor's degree thesis (electrical engineering), I don't have to simultaneously LEARN an applicable programming language while trying to obtain good results in the project. "How to go from basic C to great application of Python", that sort of thing.
Any specific bits of code to make a great solution to this problem would also be appreciated, I need to learn good algorithms.. I am envisioning 3 situations. If the value is zero or single digit, if it is of odd length, and if it is of even length. I was planning to write for loops...
PS: The problem is: Find the highest value product of two 3 digit integers that is also a palindrome.
A pythonic way to determine if a given value is a palindrome:
str(n) == str(n)[::-1]
Explanation:
We're checking if the string representation of n equals the inverted string representation of n
The [::-1] slice takes care of inverting the string
After that, we compare for equality using ==
An alternative to the rather unintuitive [::-1] syntax is this:
>>> test = "abcba"
>>> test == ''.join(reversed(test))
True
The reversed function returns a reversed sequence of the characters in test.
''.join() joins those characters together again with nothing in between.
Just for the record, and for the ones looking for a more algorithmic way to validate if a given string is palindrome, two ways to achieve the same (using while and for loops):
def is_palindrome(word):
letters = list(word)
is_palindrome = True
i = 0
while len(letters) > 0 and is_palindrome:
if letters[0] != letters[(len(letters) - 1)]:
is_palindrome = False
else:
letters.pop(0)
if len(letters) > 0:
letters.pop((len(letters) - 1))
return is_palindrome
And....the second one:
def is_palindrome(word):
letters = list(word)
is_palindrome = True
for letter in letters:
if letter == letters[-1]:
letters.pop(-1)
else:
is_palindrome = False
break
return is_palindrome
The awesome part of python is the things you can do with it. You don't have to use indexes for strings.
The following will work (using slices)
def palindrome(n):
return n == n[::-1]
What it does is simply reverses n, and checks if they are equal. n[::-1] reverses n (the -1 means to decrement)
"2) My for loop (in in range (999, 100, -1), is this a bad way to do it in Python?"
Regarding the above, you want to use xrange instead of range (because range will create an actual list, while xrange is a fast generator)
My opinions on question 3
I learned C before Python, and I just read the docs, and played around with it using the console. (and by doing Project Euler problems as well :)
Below the code will print 0 if it is Palindrome else it will print -1
Optimized Code
word = "nepalapen"
is_palindrome = word.find(word[::-1])
print is_palindrome
Output:
0
word = "nepalapend"
is_palindrome = word.find(word[::-1])
print is_palindrome
Output:
-1
Explaination:
when searching the string the value that is returned is the value of the location that the string starts at.
So when you do word.find(word[::-1]) it finds nepalapen at location 0 and [::-1] reverses nepalapen and it still is nepalapen at location 0 so 0 is returned.
Now when we search for nepalapend and then reverse nepalapend to dnepalapen it renders a FALSE statement nepalapend was reversed to dnepalapen causing the search to fail to find nepalapend resulting in a value of -1 which indicates string not found.
Another method print true if palindrome else print false
word = "nepalapen"
print(word[::-1]==word[::1])
output:
TRUE
There is also a functional way:
def is_palindrome(word):
if len(word) == 1: return True
if word[0] != word[-1]: return False
return is_palindrome(word[1:-1])
I know that this question was answered a while ago and i appologize for the intrusion. However,I was working on a way of doing this in python as well and i just thought that i would share the way that i did it in is as follows,
word = 'aibohphobia'
word_rev = reversed(word)
def is_palindrome(word):
if list(word) == list(word_rev):
print'True, it is a palindrome'
else:
print'False, this is''t a plindrome'
is_palindrome(word)
There is much easier way I just found. It's only 1 line.
is_palindrome = word.find(word[::-1])
The most pythonic way to do this is indeed using the slicing notation to reverse the string as mentioned already:
def is_palindrome(string: str) -> bool:
return string == string[::-1]
In some other occasions though (like technical interviews), you may have to write a "proper" algorithm to find the palindrome. In this case, the following should do the trick:
def is_palindrome(string: str) -> bool:
start = 0
end = len(string) - 1
while end >= start:
if string[end] != string[start]:
return False
start += 1
end -= 1
return True
Set pointers to the start and end of the string
Iterate while end exceeds start
If the character in end and start indices don't match then this is not a palindrome, otherwise keep comparing
Increase start pointer by 1
Decrease end pointer by 1
Test Cases:
import unittest
class Test(unittest.TestCase):
palindromes = ['a', 'aa', 'aba', '12321']
non_palindromes = ['ab', 'aab', 'cacacc']
def test_is_palindrome(self):
for case in self.palindromes:
self.assertTrue(is_palindrome(case))
for case in self.non_palindromes:
self.assertFalse(is_palindrome(case))
if __name__ == '__main__':
unittest.main()
You could use this one-liner that returns a bool value:
str(x)==str(x)[::-1]
This works both for words and numbers thanks to the type casting...
Here a case insensitive function since all those solutions above are case sensitive.
def Palindrome(string):
return (string.upper() == string.upper()[::-1])
This function will return a boolean value.
doing the Watterloo course for python, the same questions is raised as a "Lesseon" find the info here:
http://cscircles.cemc.uwaterloo.ca/13-lists/
being a novice i solved the problem the following way:
def isPalindrome(S):
pali = True
for i in range (0, len(S) // 2):
if S[i] == S[(i * -1) - 1] and pali is True:
pali = True
else:
pali = False
print(pali)
return pali
The function is called isPalindrome(S) and requires a string "S".
The return value is by default TRUE, to have the initial check on the first if statement.
After that, the for loop runs half the string length to check if the character from string "S" at the position "i" is the same at from the front and from the back.
If once this is not the case, the function stops, prints out FALSE and returns false.
Cheers.kg
If the string has an uppercase or non-alphabetic character then the function converts all characters to lowercase and removes all non-alphabetic characters using regex finally it applies palindrome check recursively:
import re
rules = [
lambda s: any(x.isupper() for x in s),
lambda s: not s.isalpha()
]
def is_palindrome(s):
if any(rule(s) for rule in rules):
s = re.sub(r'[^\w]', '', s).lower()
if len(s) < 2:
return True
if s[0] != s[-1]:
return False
return is_palindrome(s[1:-1])
string = 'Are we not drawn onward, we few, drawn onward to new era?'
print(is_palindrome(string))
the output is True for the input above.
maybe you can try this one:
list=input('enter a string:')
if (list==list[::-1]):
print ("It is a palindrome")
else:
print("it is not palindrome")
You are asking palindrome in python. palindrome can be performed on strings, numbers and lists. However, I just posted a simple code to check palindrome of a string.
# Palindrome of string
str=raw_input("Enter the string\n")
ln=len(str)
for i in range(ln/2) :
if(str[ln-i-1]!=str[i]):
break
if(i==(ln/2)-1):
print "Palindrome"
else:
print "Not Palindrome"
The real easy way to do that it is
word = str(raw_input(""))
is_palindrome = word.find(word[::-1])
if is_palindrome == 0:
print True
else:
print False
And if/else here just for fancy looks. The question about palindrome was on Amazon's interview for QA
Assuming a string 's'
palin = lambda s: s[:(len(s)/2 + (0 if len(s)%2==0 else 1)):1] == s[:len(s)/2-1:-1]
# Test
palin('654456') # True
palin('malma') # False
palin('ab1ba') # True
word = "<insert palindrome/string>"
reverse = word[::-1]
is_palindrome = word.find(reverse)
print is_palindrome
This was a question in Udacity comp 101, chapter 1. Gives a 0 for palindrome gives a -1 for not. Its simple, and does not use loops.
I wrote this code:
word = input("enter: ")
word = ''.join(word.split())`
for x in range(len(word)):
if list(word)[x] == ((list(word)[len(word)-x-1])):
if x+1 == len(word):
print("its pali")
and it works.
it gets the word, then removes the spaces and turns it into a list
then it tests if the first letter is equal to the last and if the 2nd is equal to 2nd last and so on.
then the 'if x+1 == len(word)' means that since x starts at 0 it becomes 1 and then for every next .. blah blah blah it works so it works.
#compare 1st half with reversed second half
# i.e. 'abba' -> 'ab' == 'ba'[::-1]
def is_palindrome( s ):
return True if len( s ) < 2 else s[ :len( s ) // 2 ] == s[ -( len( s ) // 2 ):][::-1]
You can use Deques in python to check palindrome
def palindrome(a_string):
ch_dequeu = Deque()
for ch in a_string:
ch_dequeu.add_rear(ch)
still_ok = True
while ch_dequeu.size() > 1 and still_ok:
first = ch_dequeu.remove_front()
last = ch_dequeu.remove_rear()
if first != last:
still_ok = False
return still_ok
class Deque:
def __init__(self):
self.items = []
def is_empty(self):
return self.items == []
def add_rear(self, item):
self.items.insert(0, item)
def add_front(self, item):
self.items.append(item)
def size(self):
return len(self.items)
def remove_front(self):
return self.items.pop()
def remove_rear(self):
return self.items.pop(0)
import string
word = input('Please select a word to test \n')
word = word.lower()
num = len(word)
x = round((len(word)-1)/2)
#defines first half of string
first = word[:x]
#reverse second half of string
def reverse_odd(text):
lst = []
count = 1
for i in range(x+1, len(text)):
lst.append(text[len(text)-count])
count += 1
lst = ''.join(lst)
return lst
#reverse second half of string
def reverse_even(text):
lst = []
count = 1
for i in range(x, len(text)):
lst.append(text[len(text)-count])
count += 1
lst = ''.join(lst)
return lst
if reverse_odd(word) == first or reverse_even(word) == first:
print(string.capwords(word), 'is a palindrome')
else:
print(string.capwords(word), 'is not a palindrome')
the "algorithmic" way:
import math
def isPalindrome(inputString):
if inputString == None:
return False
strLength = len(inputString)
for i in range(math.floor(strLength)):
if inputString[i] != inputString[strLength - 1 - i]:
return False
return True
There is another way by using functions, if you don't want to use reverse
#!/usr/bin/python
A = 'kayak'
def palin(A):
i = 0
while (i<=(A.__len__()-1)):
if (A[A.__len__()-i-1] == A[i]):
i +=1
else:
return False
if palin(A) == False:
print("Not a Palindrome")
else :
print ("Palindrome")
It looks prettier with recursion!
def isPalindrome(x):
z = numToList(x)
length = math.floor(len(z) / 2)
if length < 2:
if z[0] == z[-1]:
return True
else:
return False
else:
if z[0] == z[-1]:
del z[0]
del z[-1]
return isPalindrome(z)
else:
return False
def is_palindrome(string):
return string == ''.join([letter for letter in reversed(string)])
print ["Not a palindrome","Is a palindrome"][s == ''.join([s[len(s)-i-1] for i in range(len(s))])]
This is the typical way of writing single line code
def pali(str1):
l=list(str1)
l1=l[::-1]
if l1==l:
print("yess")
else:
print("noo")
str1="abc"
a=pali(str1)
print(a)
I tried using this:
def palindrome_numer(num):
num_str = str(num)
str_list = list(num_str)
if str_list[0] == str_list[-1]:
return True
return False
and it worked for a number but I don't know if a string
def isPalin(checkWord):
Hsize = len(lst)/2
seed = 1
palind=True
while seed<Hsize+1:
#print seed,lst[seed-1], lst [-(seed)]
if(lst[seed-1] != lst [-seed]):
palind = False
break
seed = seed+1
return palind
lst = 'testset'
print lst, isPalin(lst)
lst = 'testsest'
print lst, isPalin(lst)
Output
testset True
testsest False

Round G - Kick Start 2020 Problem Kick_Start Wrong Answer

Problem:
Ksenia is very fond of reading so she kicks off each day by reading a
fragment from her favourite book before starting with the rest of her
morning routine. A fragment is simply a substring of the text. Ksenia
is somewhat superstitious and believes that her day will be lucky if
the fragment she reads starts with the string KICK, then goes on with
0 or more characters, and eventually ends with the string START, even
if the overall fragment makes little sense.
Given the text of the book, count the number of different lucky
fragments that Ksenia can read before the book gets old and she needs
to buy another one. Two fragments are considered to be different if
they start or end at different positions in the text, even if the
fragments read the same. Also note that different lucky fragments may
overlap.
Input:
The first line of the input gives the number of test cases T. T lines
follow, each containing a single string S consisting of upper case
English letters only.
Output:
For each test case, output one line containing Case #x: y, where x is
the test case number (starting from 1) and y is the number of
different lucky fragments in the text of this test case.
Limits:
Memory limit: 1 GB. 1 ≤ T ≤ 100. S consists of upper-case English
letters only.
Test Set 1:
Time limit: 20 seconds.
1 ≤ |S| ≤ 1000.
Test Set 2:
Time limit: 40 seconds.
1 ≤ |S| ≤ 105.
Sample:
Input
3
AKICKSTARTPROBLEMNAMEDKICKSTART
STARTUNLUCKYKICK
KICKXKICKXSTARTXKICKXSTART
Output
Case #1: 3
Case #2: 0
Case #3: 5
I tried solving it using Python. The logic I tried using is to find indices for substring 'KICK' and substring 'START' and find number of START appearing after every 'KICK'.
I'm getting wrong answer I don't understand what edge cases I'm missing.
Here is the code:
import re
t = int(input())
for i in range(t):
text = input()
matches = 0
temp1 = [m.start() for m in re.finditer('KICK',text)]
temp2 = [m.start() for m in re.finditer('START',text)]
if len(temp1) == 0 or len(temp2) == 0:
matches = 0
else:
for ele in temp1:
for x in temp2:
if(x > ele):
matches = matches + 1
print("Case "+"#"+str(i+1)+": "+str(matches))
Finally I found the cases the code misses.
re.finditer() can only count non-overlapping matches and hence strings like 'KICKICK' would result in counting KICK only for 1 time rather than 2.
re.finditer(pattern, string, flags=0)
Return an iterator yielding MatchObject instances over all non-overlapping matches for the RE pattern in string.The string is scanned left-to-right, and matches are returned in the order found. Empty matches are included in the result.
Here is my code:
t = int(input())
for x in range(t):
s = input()
ans = 0
k = 0
for i in range(len(s)-4):
if s[i:i+4] == "KICK":
k += 1
if s[i:i+5] == "START" and k != 0:
ans += k
print("Case #{}: {}".format(x+1, ans))
You are not considering all the possibilities. The code just shows how many time the KICK and START occurs
I Hope this works.
T=int(input())
for x in range(1, T + 1):
P=input()
c=0
for i in range(0,len(P)-4+1):
if (P[i:i+4]=="KICK"):
for j in range(i+4,len(P)-5+1):
if (P[j:j+5]=="START"):
c=c+1
print("Case #{}: {}".format(x, c), flush = True)

How to efficiently remove single letter words in Python

I want to remove single letter words such as a, i e, e g, b f f, y o l o, c y l using a Python function.
My current code looks follows.
def remove_single_letters(concept):
mystring = "valid"
if len(concept) == 1:
mystring = "invalid"
if len(concept)>1:
validation = []
splits = concept.split()
for item in splits:
if len(item) > 1:
validation.append("valid")
if len(validation) != 1:
mystring = "invalid"
return mystring
print(remove_single_letters("b f f"))
It works fine. However, I am wondering if there is a more efficient way (with lesser time) of doing it in python.
Here is a single line solution:
def remove_single_letters(concept):
return ["valid", "invalid"][concept.count(" ") >= len(concept) // 2]
Update: Note that this is shorter and cool looking but does not necessarily run faster.
Explanation:
concept.count(" "): Returns the number of spaces in string
>= len(concept) // 2: Returns True if more than half of the string is spaces (it fails when there are multiple spaces between legitimate words as #user202729 mentioned)
["valid", "invalid"][result]: This part is just for fun: It returns the first element if the result is False and the second element if the result is True (because False is equal to 0 and True is equal to 1).
I would go for a more concise solution (yet not faster as both solutions are of O(n)) if you want to check if any 1 letter character exists in the string:
remove_single_letters = lambda concept:"invalid" if 1 in [len(item) for item in concept.split()] else "valid"
print(remove_single_letters("a b c"))
#prints invalid
An ordinary function would be like this:
def remove_single_letters(concept):
return "invalid" if 1 in [len(item) for item in concept.split()] else "valid"
They both check the length of elements in the split input to find any item with length of 1 and is insensitive to multiple spaces thanks to split().
If you want to check the strings that are totally made up of single characters:
def remove_single_letters(concept):
u = set(len(item) for item in concept.split())
return "invalid" if len(u) == 1 and 1 in u else "valid"

I'm looking to print the length of the longest and shortest words but am unsure where I'm going wrong

import string
a = input("Input a string ")
aSplit = a.split()
for aString in aSplit:
print (aString)
sLen =(len(aString))
def minmax(sLen):
if len(1) == 0 : return None
smallest = largest = 1[0]
for n in 1 :
if n < smallest : smallest = n
elif n > largest : largest = n
return (smallest, largest)
print (minmax, sLen)
What I am currently getting as my print result for minmax:
function ex4. locals .minmax at 0x03FFD1E0 6
I'm looking to make it prettier and print the minimum value.
There are many issues with your code but the main problem is how you are calling the function. You should be calling it like print(minmax(sLen)), and even then you wouldn't be getting the results you expect because sLen represents the length of the last element in your aSplit list.
To get the length of the longest and shortest words from a string, as per your question, you can use the code below.
def minmax(my_string):
string_list = my_string.split() # Split string into list
sorted_list = sorted(map(len, string_list)) # Apply len() to all elements of list and sort
output = (sorted_list[0], sorted_list[-1]) # Use list indexing to get first and last element of list
return output

Finding the index at which upon removing element string becomes palindrome

I'm writing the solution to this HackerRank problem - https://www.hackerrank.com/challenges/palindrome-index
I've tried this code:
T = int(raw_input())
for t in xrange(T):
s = raw_input()
index = -1
if s != s[::-1]:
for i in xrange(len(s)):
temp = s[:i:] + s[i+1::]
if temp == temp[::-1]:
index = i
break
print index
But when I submit it, out of the 14 test cases, around 8 take a long time to compute (~5-7 seconds) and 1 of them takes more than 10 seconds, so HackerRank doesn't even show the result (whether it gave the right output).
It seems my code is inefficient. Please help me out in making it run faster.
The easiest way to speed the code would be to remove slicing for every index in case that string isn't a palindrome. In case of maximum length string which is not a palindrome following line will generate over 200000 slices: temp = s[:i:] + s[i+1::].
You could start checking the string from start and beginning until you spot a difference. Once found you can generate slice which has either first or last letter removed and check if that's a palindrome. In case you removed the first character and result wasn't a palindrome you know that last character is the correct solution since the problem statement guarantees that:
T = int(raw_input())
for t in xrange(T):
s = raw_input()
length = len(s)
for i in xrange(length / 2):
if s[i] != s[length - i - 1]:
if s[i + 1:length - i] == s[length - i - 1:i:-1]:
print i
else:
print length - i - 1
break
else:
print -1
The most efficient way would be to check from both sides left and right and break on inequality:
for i in range(int(input())):
s=input()
if s==s[::-1]:
print(-1)
else:
for i in range(int(len(s)/2)):
if s[i]!=s[len(s)-1-i]:
print(i if ((s[:i]+s[i+1:])==(s[:i]+s[i+1:])[::-1]) else len(s)-1-i)
break
Apparently I'm a member of that site as well, executed my code and it passes all test cases with 0.01 s and 0.02s

Categories

Resources