I need to check if the input is a palindrome.
I converted the input to a string and compared the input with the reverse of the input using list slicing. I want to learn a different way without converting input to a string.
def palindrome(n):
num = str(n)
if num == num[::-1]:
return True
Assuming that n is a number, you can get digits from right to left and build a number with those digits from left to right:
n = 3102
m = n
p = 0
while m:
p = p*10 + m%10 # add the rightmost digit of m to the right of p
m //= 10 # remove the rightmost digit of m
print(p) # 2013
Hence the function:
def palindrome(n):
m = n
p = 0
while m:
p = p*10 + m%10
m //= 10
return p == n
Note that:
if num == num[::-1]:
return True
will return None if num != num[::-1] (end of the function). You should write:
if num == num[::-1]:
return True
else:
return False
Or (shorter and cleaner):
return num == num[::-1]
There can be 2 more approaches to that as follows:
Iterative Method: Run loop from starting to length/2 and check first character to last character of string and second to second last one and so on. If any character mismatches, the string wouldn’t be palindrome.
Sample Code Below:
def isPalindrome(str):
for i in xrange(0, len(str)/2):
if str[i] != str[len(str)-i-1]:
return False
return True
One Extra Variable Method: In this method, user take a character of string one by one and store in a empty variable. After storing all the character user will compare both the string and check whether it is palindrome or not.
Sample Code Below:
def isPalindrome(str):
w = ""
for i in str:
w = i + w
if (str==w):
return True
return False
You can try the following approach:
Extract all the digits from the number n
In each iteration, append the digit to one list (digits) and at that digit at the beginning of another list (reversed_digits)
Once all digits have been extracted, compare both lists
def palindrome(n):
digits = []
reversed_digits = []
while n > 0:
digit = n % 10
digits.append(digit)
reversed_digits.insert(0, digit)
n //= 10
return digits == reversed_digits
Note: this might not be the most efficient way to solve this problem, but I think it is very easy to understand.
Related
Python.
It's a problem:
The algorithm receives a natural number N > 1 as input and builds a new number R from it as follows:
We translate the number N into binary notation.
Invert all bits of the number except the first one.
Convert to decimal notation.
Add the result with the original number N.
The resulting number is the desired number R. Indicate the smallest odd number N for which the result of this algorithm is greater than 310. In your answer, write this number in decimal notation.
This is my solution:
for n in range(2, 10000):
s = bin(n)[2:]
for i in range(len(s)):
if s[i+1] == 0:
s[i] = '1'
else:
s[i] = 'k'
for i in range(len(s)):
if s[i] == 'k':
s[i] = '0'
h = int(s, 2)
r = h + n
if n % 2 == 1 and r > 310:
print(n)
break
So it doesn't work and i dont know why. I am now preparing for the exam, so I would be grateful if you could explain the reason to me
the bin function returns a string and my idea is to go through the binary elements of this string, starting from the second element, to replace 0 with 1, and 1 with k. Then iterate over the elements of a new line again and replace k with 0
Took me longer than I expected but feels good.
Comments might make it look chaotic but will make it easily understandable.
#since N is supposed to be odd and >1 the loop is being run from 3
for N in range(3, 10000,2):
#appending binary numbers to the list bin_li
bin_li=[]
bin_li.append((bin(N)[2:]))
for i in bin_li:
#print("bin_li item :",i)
#storing 1st digit to be escaped in j
j=i[:1]
#reversing the digits
for k in i[1:]:
if k=='0':
#putting together the digits after reversing
j=j+'1'
else:
j=j+'0'
#print("reversed item :",j) #note first digit is escaped
#converting back to decimal
dec=int(j,2)
R=dec+N
#print("current sum:---------" ,R)
if R > 310:
print("The number N :",N)
print("The reversed binary number:",dec)
print("Sum :",R)
break
#break will only break the inner loop
# for reference https://www.geeksforgeeks.org/how-to-break-out-of-multiple-loops-in-python/
else:
continue
break
I'm asked to write a function generate_palindrome() that takes a given positive integer number n and applies the following procedure to it:
(i) Check if the number is palindrome. If it is, then return it otherwise continue with the next step.
(ii) Reverse the number and calculate the sum of the original number with the reversed number.
(iii) Repeat from (i) (until a palindrome is found.)
I wrote this function:
def generate_palindrome(n):
numbers = list(str(n))
for i in range(len(numbers)):
if numbers[i] == numbers[-i-1]:
return n
else:
while numbers[i] != numbers[-i-1]:
rev = list(reversed(numbers))
rev_num = int(''.join(rev))
n = n + rev_num
return n
I don't know for what reason when I try a random number that is not already palindrome, the code doesn't respond, it's still running until an indefinite amount of time. I tried changing it with an if code but it doesn't iterate my function, so I think my only chance is with the while code, but maybe I'm the one who's wrong. What do you think?
I think that you should've added a broken functionality to your while loop so that when a specific condition is achieved it breaks. And I think that the indentation of the last return statement is wrong. :)
Here you go:
#!/usr/bin/env python3
def generate_palindrome(num: int):
if str(num) == str(num)[::-1]:
return num
else:
while str(num) != str(num)[::-1]:
rev = int(str(num)[::-1])
num += rev
return num
if __name__ == '__main__':
print(generate_palindrome(212)) # prints 212
print(generate_palindrome(12)) # prints 33
print(generate_palindrome(43)) # prints 77
This is the best solution:
def generate_palindrome(n):
while True:
number = list(str(n))
num = ''
if number[::-1] == number:
for i in number:
num = num + i
print(num)
break
print(a)
else:
for i in number:
num = num + i
n = int(num) + int(num[::-1])
generate_palindrome()
I am given a string and I have to determine whether it can be rearranged into a palindrome.
For example: "aabb" is true.
We can rearrange "aabb" to make "abba", which is a palindrome.
I have come up with the code below but it fails in some cases. Where is the problem and how to fix this?
def palindromeRearranging(inputString):
a = sorted(inputString)[::2]
b = sorted(inputString)[1::2]
return b == a[:len(b)]
def palindromeRearranging(inputString):
return sum(map(lambda x: inputString.count(x) % 2, set(inputString))) <= 1
this code counts occurrence for every character in string. in palindromes there is one character with odd occurrence if length of string is odd, if length of string is even then no character has odd occurance.
see here
def palindromeRearranging(inputString):
elements = {c:inputString.count(c) for c in set(inputString)}
even = [e % 2 == 0 for e in elements.values()]
return all(even) or (len(inputString) % 2 == 1 and even.count(False) == 1)
It counts each character number of appearances, and checks whether all elements appear an even number of times or if the length of the input string is odd, checks whether only one character appears an odd number of times.
Python3
def palindromeArrange (string):
string = list(string)
for i in range (len(string)):
"""if the string has even element count"""
if len(string) % 2 == 0 and len(string)/2 == len (set (string)):
return True
"""if the string has odd element count"""
if len(string) - ((len(string)-1)/2) == len (set (string)):
return True
return False
One liner using list comprehension in Python3
return len([x for x in set(inputString) if inputString.count(x) % 2 != 0]) <= 1
Basically counts those characters that have counts that aren't divisible by 2.
For even strings it would be zero, and for odd strings, it would be one.
The solution I can think of right away has time complexity is O(n). The assumption is, palindrome can not be made if there is more than one character with the odd count.
def solution(inputString):
string = list(inputString)
n = len(string)
s_set= set(string)
from collections import Counter
dic = Counter(string)
k =0 #counter for odd characters
for char in s_set:
if dic.get(char)%2!=0:
k+=1
if k>1:
return False
else:
return True
How can I shuffle two strings s||t (shuffle(s, t)) with the given requirement that the first char always stands in front of the second one in s and t as well no matter we shuffle. The result returns as a set of strings without duplicates.
I have the following test:
print(shuffle('ab', 'cd'))
Result:
['abcd', 'acbd', 'acdb', 'cabd', 'cadb', 'cdab']
Thanks a lot.
This method will shuffle two strings and return a list of shuffles between them where the order of the characters is the same as in the original strings. If there are duplicate characters there will be duplicate results as well.
def shuffle(s1, s2):
if len(s1) == 1:
return [s2[:i] + s1 + s2[i:] for i in range(len(s2) + 1)]
if len(s2) == 1:
return [s1[:i] + s2 + s1[i:] for i in range(len(s1) + 1)]
return [s1[0]+ s for s in shuffle(s1[1:], s2)] + [s2[0] + s for s in shuffle(s1, s2[1:])]
print shuffle("ab", "cd")
It works by getting the first character of each string and recursively shuffling the rest and adding this character to each element in the list. When there is one character remaining on each of the strings it returns a list where the character is added in each position of the other string. Hope it helps.
So you can apply a condition on final shuffled list to generate a new list from the shuffled one:
S=shuffle('ab','cd')
nl=[]
for w in S:
if(w.index('a')<w.index('b') and w.index('c')<w.index('d')):
nl.append(w)
So nl is your new list as per your requirement:)
If I understood the question correctly, this should work. Note, as you add letters to this, it becomes a long running problem. 4 letters have 6 possible combination for each entry in the list. 8 letters have 5,040 possible combinations for each entry in the list.
import random
import math
InputList = ['ab','cd']
PossibleUniqueCombinations = math.factorial(len("".join(InputList))-1)
print (PossibleUniqueCombinations)
TargetList = []
UniqueCombinationList = []
for lst in InputList:
UniqueCnt = 0
FirstChar = lst[0]
TheRest = list(lst[1:])
while UniqueCnt < PossibleUniqueCombinations:
if InputList.index(lst) == 0:
LeftList = []
else:
LeftList = InputList[0:InputList.index(lst)]
RightList = list(InputList[InputList.index(lst)+1:])
TargetList = LeftList + TheRest + RightList
TargetStr = ''.join(TargetList)
TargetStr = ''.join(random.sample(TargetStr, len(TargetStr)))
ShuffledStr = FirstChar + ''.join(TargetStr)
try:
FndIdx = UniqueCombinationList.index(ShuffledStr)
except ValueError:
UniqueCombinationList.append(ShuffledStr)
UniqueCnt += 1
for combo in UniqueCombinationList:
print(combo)
How to find that any anagram of String 1 is sub string of String 2?
Eg :-
String 1 =rove
String 2=stackoverflow
So it will return true as anagram of "rove" is "over" which is sub-string of String 2
On edit: my first answer was quadratic in the worst case. I've tweaked it to be strictly linear:
Here is an approach based on the notion of a sliding window: Create a dictionary keyed by the letters of the first dictionary with frequency counts of the letters for the corresponding values. Think of this as a dictionary of targets which need to be matched by m consecutive letters in the second string, where m is the length of the first string.
Start by processing the first m letters in the second string. For each such letter if it appears as a key in the target dictionary decrease the corresponding value by 1. The goal is to drive all target values to 0. Define discrepancy to be the sum of the absolute values of the values after processing the first window of m letters.
Repeatedly do the following: check if discrepancy == 0 and return Trueif it does. Otherwise -- take the character m letters ago and check if it is a target key and if so -- increase the value by 1. In this case, this either increases or decreases the discrepancy by 1, adjust accordingly. Then get the next character of the second string and process it as well. Check if it is a key in the dictionary and if so adjust the value and the discrepancy as appropriate.
Since there are no nested loop and each pass through the main loop involves just a few dictionary lookups, comparisons, addition and subtractions, the overall algorithm is linear.
A Python 3 implementation (which shows the basic logic of how the window slides and the target counts and discrepancy are adjusted):
def subAnagram(s1,s2):
m = len(s1)
n = len(s2)
if m > n: return false
target = dict.fromkeys(s1,0)
for c in s1: target[c] += 1
#process initial window
for i in range(m):
c = s2[i]
if c in target:
target[c] -= 1
discrepancy = sum(abs(target[c]) for c in target)
#repeatedly check then slide:
for i in range(m,n):
if discrepancy == 0:
return True
else:
#first process letter from m steps ago from s2
c = s2[i-m]
if c in target:
target[c] += 1
if target[c] > 0: #just made things worse
discrepancy +=1
else:
discrepancy -=1
#now process new letter:
c = s2[i]
if c in target:
target[c] -= 1
if target[c] < 0: #just made things worse
discrepancy += 1
else:
discrepancy -=1
#if you get to this stage:
return discrepancy == 0
Typical output:
>>> subAnagram("rove", "stack overflow")
True
>>> subAnagram("rowe", "stack overflow")
False
To stress-test it, I downloaded the complete text of Moby Dick from Project Gutenberg. This has over 1 million characters. "Formosa" is mentioned in the book, hence an anagram of "moors" appears as a substring of Moby Dick. But, not surprisingly, no anagram of "stackoverflow" appears in Moby Dick:
>>> f = open("moby dick.txt")
>>> md = f.read()
>>> f.close()
>>> len(md)
1235186
>>> subAnagram("moors",md)
True
>>> subAnagram("stackoverflow",md)
False
The last call takes roughly 1 second to process the complete text of Moby Dick and verify that no anagram of "stackoverflow" appears in it.
Let L be the length of String1.
Loop over String2 and check if each substring of length L is an anagram of String1.
In your example, String1 = rove and String2 = stackoverflow.
stackoverflow
stac and rove are not anagrams, so move to the next substring of length L.
stackoverflow
tack and rove are not anagrams, and so on till you find the substring.
A faster method would be to check if the last letter in the current substring is present in String1 i.e., once you find that stac and rove are not anagrams, and see that 'c' (which is the last letter of the current substring) is not present in rove, you can simply skip that substring entirely and get the next substring from 'k'.
i.e. stackoverflow
stac and rove are not anagrams. 'c' is not present in 'rove', so simply skip over this substring and check from 'k':
stackoverflow
This will significantly reduce the number of comparisons.
Edit:
Here is a Python 2 implementation of the method explained above.
NOTE: This implementation works under the assumption that all characters in both strings are in lowercase and they consist only of the characters a -z.
def isAnagram(s1, s2):
c1 = [0] * 26
c2 = [0] * 26
# increase character counts for each string
for i in s1:
c1[ord(i) - 97] += 1
for i in s2:
c2[ord(i) - 97] += 1
# if the character counts are same, they are anagrams
if c1 == c2:
return True
return False
def isSubAnagram(s1, s2):
l = len(s1)
# s2[start:end] represents the substring in s2
start = 0
end = l
while(end <= len(s2)):
sub = s2[start:end]
if isAnagram(s1, sub):
return True
elif sub[-1] not in s1:
start += l
end += l
else:
start += 1
end += 1
return False
Output:
>>> print isSubAnagram('rove', 'stackoverflow')
True
>>> print isSubAnagram('rowe', 'stackoverflow')
False
It can be done in O(n^3) pre-processing, and O(klogk) per query where: n is the size of the "given string" (string 2 in your example) and k is the size of the query (string 1 in your example).
Pre process:
For each substring s of string2: //O(n^2) of those
sort s
store s in some data base (hash table, for example)
Query:
given a query q:
sort q
check if q is in the data base
if it is - it's an anagram of some substring
otherwise - it is not.
This answer assumes you are going to check multiple "queries" (string 1's) for a single string (string 2), and thus tries to optimize the complexity for each query.
As discussed in comments, you can do the pro-process step lazily - that means, when you first encounter a query of length k insert to the DS all substrings of length k, and proceed as original suggestion.
You may need to create all the possible combination of String1 that is rove like rove,rvoe,reov.. Then check this any of this combination is in String2.
//Two string are considered and check whether Anagram of the second string is
//present in the first string as part of it (Substring)
//e.g. 'atctv' 'cat' will return true as 'atc' is anagram of cat
//Similarly 'battex' is containing an anagram of 'text' as 'ttex'
public class SubstringIsAnagramOfSecondString {
public static boolean isAnagram(String str1, String str2){
//System.out.println(str1+"::" + str2);
Character[] charArr = new Character[str1.length()];
for(int i = 0; i < str1.length(); i++){
char ithChar1 = str1.charAt(i);
charArr[i] = ithChar1;
}
for(int i = 0; i < str2.length(); i++){
char ithChar2 = str2.charAt(i);
for(int j = 0; j<charArr.length; j++){
if(charArr[j] == null) continue;
if(charArr[j] == ithChar2){
charArr[j] = null;
}
}
}
for(int j = 0; j<charArr.length; j++){
if(charArr[j] != null)
return false;
}
return true;
}
public static boolean isSubStringAnagram(String firstStr, String secondStr){
int secondLength = secondStr.length();
int firstLength = firstStr.length();
if(secondLength == 0) return true;
if(firstLength < secondLength || firstLength == 0) return false;
//System.out.println("firstLength:"+ firstLength +" secondLength:" + secondLength+
//" firstLength - secondLength:" + (firstLength - secondLength));
for(int i = 0; i < firstLength - secondLength +1; i++){
if(isAnagram(firstStr.substring(i, i+secondLength),secondStr )){
return true;
}
}
return false;
}
public static void main(String[] args) {
System.out.println("isSubStringAnagram(xyteabc,ate): "+ isSubStringAnagram("xyteabc","ate"));
}
}