Python: поиск самых длинных палиндромов в слове и палиндромов в слове / строке

Итак, вот код, который я написал, чтобы найти палиндромы в слове (чтобы проверить, есть ли палиндромы в слове, включая само слово) Условие: пробелы между символами подсчитываются и не игнорируются. Пример: А, но туба - палиндром, но технически в пространствах, участвующих в настоящее время это не так. так что это критерии.

Исходя из вышеизложенного, следующий код обычно должен работать. Вы можете попробовать самостоятельно с различными тестами, чтобы проверить, если этот код дает какую-либо ошибку.

def pal(text):
    """

    param text: given string or test
    return: returns index of longest palindrome and a list of detected palindromes stored in temp
    """
    lst = {}
    index = (0, 0)
    length = len(text)
    if length <= 1:
        return index
    word = text.lower()  # Trying to make the whole string lower case
    temp = str()
    for x, y in enumerate(word):
        # Try to enumerate over the word
        t = x
        for i in xrange(x):
            if i != t+1:
                string = word[i:t+1]
                if string == string[::-1]:
                    temp = text[i:t+1]
                    index = (i, t+1)
                    lst[temp] = index
    tat = lst.keys()
    longest = max(tat, key=len)
    #print longest
    return lst[longest], temp

И вот несуществующая версия этого. Я имею в виду, что я попытался начать с середины и обнаружить палиндромы, повторяя с начала и проверяя для каждого более высокого и более низкого индексов для символа, проверяя, являются ли они равными символами. если они тогда, я проверяю, является ли это палиндромом как регулярная проверка палиндрома. вот что я сделал

def pal(t):
    text = t.lower()
    lst = {}
    ptr = ''
    index = (0, 0)
    #mid = len(text)/2
    #print mid
    dec = 0
    inc = 0
    for mid, c in enumerate(text):
        dec = mid - 1
        inc = mid + 1
        while dec != 0 and inc != text.index(text[-1]):
            print 'dec {}, inc {},'.format(dec, inc)
            print 'text[dec:inc+1] {}'.format(text[dec:inc+1])
            if dec<0:
                dec = 0
            if inc > text.index(text[-1]):
                inc = text.index(text[-1])
            while text[dec] != text[inc]:
                flo = findlet(text[inc], text[:dec])
                fhi = findlet(text[dec], text[inc:])
                if len(flo) != 0 and len(fhi) != 0 and text[flo[-1]] == text[fhi[0]]:
                    dec = flo[-1]
                    inc = fhi[0]
                    print ' break if'
                    break
                elif len(flo) != 0 and text[flo[-1]] == text[inc]:
                    dec = flo[-1]
                    print ' break 1st elif'
                    break
                elif len(fhi) != 0 and text[fhi[0]] == text[inc]:
                    inc = fhi[0]
                    print ' break 2nd elif'
                    break
                else:
                    dec -= 1
                    inc += 1
                    print ' break else'
                    break
            s = text[dec:inc+1]
            print ' s {} '.format(s)
            if s == s[::-1]:
                index = (dec, inc+1)
                lst[s] = index
            if dec > 0:
                dec -= 1
            if inc < text.index(text[-1]):
                inc += 1
    if len(lst) != 0:
        val = lst.keys()
        longest = max(val, key = len)
        return lst[longest], longest, val
    else:
        return index

findlet() fun:

def findlet(alpha, string):
    f = [i for i,j in enumerate(string) if j == alpha]
    return f

Иногда это работает:

pal('madem')
dec -1, inc 1,
text[dec:inc+1] 
 s m 
dec 1, inc 3,
text[dec:inc+1] ade
 break 1st elif
 s m 
dec 2, inc 4,
text[dec:inc+1] dem
 break 1st elif
 s m 
dec 3, inc 5,
text[dec:inc+1] em
 break 1st elif
 s m 
Out[6]: ((0, 1), 'm', ['m'])

pal('Avid diva.')
dec -1, inc 1,
text[dec:inc+1] 
 break 2nd if
 s avid div 
dec 1, inc 3,
text[dec:inc+1] vid
 break else
 s avid  
dec 2, inc 4,
text[dec:inc+1] id 
 break else
 s vid d 
dec 3, inc 5,
text[dec:inc+1] d d
 s d d 
dec 2, inc 6,
text[dec:inc+1] id di
 s id di 
dec 1, inc 7,
text[dec:inc+1] vid div
 s vid div 
dec 4, inc 6,
text[dec:inc+1]  di
 break 1st elif
 s id di 
dec 1, inc 7,
text[dec:inc+1] vid div
 s vid div 
dec 5, inc 7,
text[dec:inc+1] div
 break 1st elif
 s vid div 
dec 6, inc 8,
text[dec:inc+1] iva
 break 1st elif
 s avid diva 
dec 8, inc 10,
text[dec:inc+1] a.
 break else
 s va. 
dec 6, inc 10,
text[dec:inc+1] iva.
 break else
 s diva. 
dec 4, inc 10,
text[dec:inc+1]  diva.
 break else
 s d diva. 
dec 2, inc 10,
text[dec:inc+1] id diva.
 break else
 s vid diva. 
Out[9]: ((0, 9), 'avid diva', ['avid diva', 'd d', 'id di', 'vid div'])

И на основании критериев / условий я поставил:

pal('A car, a man, a maraca.')
dec -1, inc 1,
text[dec:inc+1] 
 break else
 s  
dec -1, inc 3,
text[dec:inc+1] 
 s a ca 
dec 1, inc 3,
text[dec:inc+1]  ca
 break if
 s a ca 
dec 2, inc 4,
text[dec:inc+1] car
 break else
 s  car, 
dec 3, inc 5,
text[dec:inc+1] ar,
 break else
 s car,  
dec 1, inc 7,
text[dec:inc+1]  car, a
 break 1st elif
 s a car, a 
dec 4, inc 6,
text[dec:inc+1] r, 
 break 1st elif
 s  car,  
dec 5, inc 7,
text[dec:inc+1] , a
 break 1st elif
 s ar, a 
dec 2, inc 8,
text[dec:inc+1] car, a 
 break 1st elif
 s  car, a  
dec 6, inc 8,
text[dec:inc+1]  a 
 s  a  
dec 5, inc 9,
text[dec:inc+1] , a m
 break else
 s r, a ma 
dec 3, inc 11,
text[dec:inc+1] ar, a man
 break else
 s car, a man, 
dec 1, inc 13,
text[dec:inc+1]  car, a man, 
 s  car, a man,  
dec 7, inc 9,
text[dec:inc+1] a m
 break else
 s  a ma 
dec 5, inc 11,
text[dec:inc+1] , a man
 break else
 s r, a man, 
dec 3, inc 13,
text[dec:inc+1] ar, a man, 
 break if
 s   
dec 8, inc 10,
text[dec:inc+1]  ma
 break if
 s  
dec 6, inc 4,
text[dec:inc+1] 
 break 1st elif
 s r 
dec 3, inc 5,
text[dec:inc+1] ar,
 break else
 s car,  
dec 1, inc 7,
text[dec:inc+1]  car, a
 break 1st elif
 s a car, a 
dec 9, inc 11,
text[dec:inc+1] man
 break else
 s  man, 
dec 7, inc 13,
text[dec:inc+1] a man, 
 break if
 s  
dec 5, inc 2,
text[dec:inc+1] 
 break 1st elif
 s c 
dec 1, inc 3,
text[dec:inc+1]  ca
 break if
 s a ca 
dec 10, inc 12,
text[dec:inc+1] an,
 break 1st elif
 s , a man, 
dec 4, inc 13,
text[dec:inc+1] r, a man, 
 break 1st elif
 s  car, a man,  
dec 11, inc 13,
text[dec:inc+1] n, 
 break 1st elif
 s  man,  
dec 7, inc 14,
text[dec:inc+1] a man, a
 s a man, a 
dec 6, inc 15,
text[dec:inc+1]  a man, a 
 s  a man, a  
dec 5, inc 16,
text[dec:inc+1] , a man, a m
 break else
 s r, a man, a ma 
dec 3, inc 18,
text[dec:inc+1] ar, a man, a mar
 break else
 s car, a man, a mara 
dec 1, inc 20,
text[dec:inc+1]  car, a man, a marac
 break else
 s a car, a man, a maraca 
dec 12, inc 14,
text[dec:inc+1] , a
 break 1st elif
 s an, a 
dec 9, inc 15,
text[dec:inc+1] man, a 
 break if
 s  
dec 7, inc 2,
text[dec:inc+1] 
 break 1st elif
 s c 
dec 1, inc 3,
text[dec:inc+1]  ca
 break if
 s a ca 
dec 13, inc 15,
text[dec:inc+1]  a 
 s  a  
dec 12, inc 16,
text[dec:inc+1] , a m
 break 1st elif
 s man, a m 
dec 8, inc 17,
text[dec:inc+1]  man, a ma
 break 1st elif
 s a man, a ma 
dec 6, inc 18,
text[dec:inc+1]  a man, a mar
 break 1st elif
 s r, a man, a mar 
dec 3, inc 19,
text[dec:inc+1] ar, a man, a mara
 s ar, a man, a mara 
dec 2, inc 20,
text[dec:inc+1] car, a man, a marac
 s car, a man, a marac 
dec 1, inc 21,
text[dec:inc+1]  car, a man, a maraca
 break 1st elif
 s a car, a man, a maraca 
dec 14, inc 16,
text[dec:inc+1] a m
 break 1st elif
 s man, a m 
dec 8, inc 17,
text[dec:inc+1]  man, a ma
 break 1st elif
 s a man, a ma 
dec 6, inc 18,
text[dec:inc+1]  a man, a mar
 break 1st elif
 s r, a man, a mar 
dec 3, inc 19,
text[dec:inc+1] ar, a man, a mara
 s ar, a man, a mara 
dec 2, inc 20,
text[dec:inc+1] car, a man, a marac
 s car, a man, a marac 
dec 1, inc 21,
text[dec:inc+1]  car, a man, a maraca
 break 1st elif
 s a car, a man, a maraca 
dec 15, inc 17,
text[dec:inc+1]  ma
 break 1st elif
 s a ma 
dec 13, inc 18,
text[dec:inc+1]  a mar
 break 1st elif
 s r, a man, a mar 
dec 3, inc 19,
text[dec:inc+1] ar, a man, a mara
 s ar, a man, a mara 
dec 2, inc 20,
text[dec:inc+1] car, a man, a marac
 s car, a man, a marac 
dec 1, inc 21,
text[dec:inc+1]  car, a man, a maraca
 break 1st elif
 s a car, a man, a maraca 
dec 16, inc 18,
text[dec:inc+1] mar
 break 1st elif
 s r, a man, a mar 
dec 3, inc 19,
text[dec:inc+1] ar, a man, a mara
 s ar, a man, a mara 
dec 2, inc 20,
text[dec:inc+1] car, a man, a marac
 s car, a man, a marac 
dec 1, inc 21,
text[dec:inc+1]  car, a man, a maraca
 break 1st elif
 s a car, a man, a maraca 
dec 17, inc 19,
text[dec:inc+1] ara
 s ara 
dec 16, inc 20,
text[dec:inc+1] marac
 break 1st elif
 s car, a man, a marac 
dec 1, inc 21,
text[dec:inc+1]  car, a man, a maraca
 break 1st elif
 s a car, a man, a maraca 
dec 18, inc 20,
text[dec:inc+1] rac
 break 1st elif
 s car, a man, a marac 
dec 1, inc 21,
text[dec:inc+1]  car, a man, a maraca
 break 1st elif
 s a car, a man, a maraca 
dec 19, inc 21,
text[dec:inc+1] aca
 s aca 
dec 21, inc 23,
text[dec:inc+1] a.
 break else
 s ca. 
dec 19, inc 23,
text[dec:inc+1] aca.
 break else
 s raca. 
dec 17, inc 23,
text[dec:inc+1] araca.
 break else
 s maraca. 
dec 15, inc 23,
text[dec:inc+1]  maraca.
 break else
 s a maraca. 
dec 13, inc 23,
text[dec:inc+1]  a maraca.
 break else
 s , a maraca. 
dec 11, inc 23,
text[dec:inc+1] n, a maraca.
 break else
 s an, a maraca. 
dec 9, inc 23,
text[dec:inc+1] man, a maraca.
 break else
 s  man, a maraca. 
dec 7, inc 23,
text[dec:inc+1] a man, a maraca.
 break else
 s  a man, a maraca. 
dec 5, inc 23,
text[dec:inc+1] , a man, a maraca.
 break else
 s r, a man, a maraca. 
dec 3, inc 23,
text[dec:inc+1] ar, a man, a maraca.
 break else
 s car, a man, a maraca. 
dec 1, inc 23,
text[dec:inc+1]  car, a man, a maraca.
 break else
 s a car, a man, a maraca. 
Out[8]: ((13, 16), ' a ', ['', ' a ', 'c', ' ', 'aca', 'ara', 'r'])

Иногда это не работает вообще:

    pal('madam')
    dec -1, inc 1,
    text[dec:inc+1] 
     s m 
    dec 1, inc 3,
    text[dec:inc+1] ada
     break 1st elif
     s m 
    dec 2, inc 4,
    text[dec:inc+1] dam
     break 1st elif
     s m 
    dec 3, inc 5,
    text[dec:inc+1] am
     break 1st elif
     s m 
    Out[5]: ((0, 1), 'm', ['m'])

Теперь, считая мадам очень хорошим палиндромом, он должен работать, и есть много случаев, которые я не проверял сам, чтобы выяснить, какие другие законные палиндромы он не обнаруживает.

Q1: почему это иногда не обнаруживает?

Q2: Я хотел бы оптимизировать свой второй код в этом отношении. Любые входы?

Вопрос 3. Какой лучший подход существует для гораздо более эффективного кода, чем мой первый код, который повторяется много раз?

17 ответов

Решение

Ваше решение кажется мне немного сложным. Просто посмотрите на все возможные подстроки и проверьте их индивидуально:

def palindromes(text):
    text = text.lower()
    results = []

    for i in range(len(text)):
        for j in range(0, i):
            chunk = text[j:i + 1]

            if chunk == chunk[::-1]:
                results.append(chunk)

    return text.index(max(results, key=len)), results

text.index() найдет только первое вхождение самого длинного палиндрома, поэтому, если вы хотите последнее, замените его на text.rindex(),

Следующая функция возвращает самый длинный палиндром, содержащийся в данной строке. Это просто немного отличается в том, что он использует itertools как предложено в этом ответе. Есть смысл абстрагироваться от генерации комбинации. Его временная сложность, очевидно, все еще кубическая. При необходимости его можно легко адаптировать для возврата индекса и / или списка палиндромов.

import itertools

def longest_palindrome(s):
    lp, lp_len = '', 0
    for start, stop in itertools.combinations(range(len(s)+1), 2):
        ss = s[start:stop]  # substring
        if (len(ss) > lp_len) and (ss == ss[::-1]):
            lp, lp_len = ss, len(ss)
    return lp

Если вам нравится рекурсивное решение, я написал рекурсивную версию. Это также интуитивно понятно.

def palindrome(s):
  if len(s) <= 1:
    return s
  elif s[0] != s[-1]:
    beginning_palindrome = palindrome(s[:-1])
    ending_palindrome = palindrome(s[1:])
    if len(beginning_palindrome) >= len(ending_palindrome):
      return beginning_palindrome
    else:
      return ending_palindrome
  else:
    middle_palindrome = palindrome(s[1:-1])
    if len(middle_palindrome) == len(s[1:-1]):
        return s[0] + middle_palindrome + s[-1]
    else:
        return middle_palindrome

Ниже приведен код, который я написал для того же вопроса. Это может быть не очень оптимизировано, но работает как шарм. Довольно легко понять и для начинающих

def longestPalindrome(s):
        pal = []
        longestpalin = s
        l = list(s)
        if len(s)>0:
            if len(s)==2:
                p = l
                if p[0]==p[1]:
                    return s
                else:
                    return l[0]
            else:
                for i in range(0,len(l)):
                    for j in range(i+1,len(l)+1):
                        p = l[i:j]
                        if p == p[::-1]:
                            if len(p)>len(pal):
                                pal = p
                                p = ''.join(p)
                                longestpalin = p
            return longestpalin
        else:
            return longestpalin

Решение Python 3: (не самое быстрое)

class Solution:
    def longestPalindrome(self, s: str) -> str:

        if s == "":
            return ""
        if len(s) == 1: 
            return s
        if len(s) == 2:
            if s == s[::-1]:
                return s
            else:
                return s[0]


        results = []

        for i in range(len(s)):
            for j in range(0, i):
                chunk = s[j:i + 1]

                if chunk == chunk[::-1]:
                    results.append(chunk)
        if results:       
            return max(results, key=len)
        else:
            return s[0]

s='stresseddesserts'
out1=[]
def substring(x):
    for i in range(len(x)):
        a=x[i:]
        b=x[:-i]
        out1.append(a)
        out1.append(b)
        
    return out1

for i in range(len(s)):
    substring(s[i:])    
final=set([item for item in out1 if len(item)>2])
final
palind={item:len(item) for item in final if item==item[::-1]}
print(palind)
sorted(palind.items(),reverse=True, key=lambda x: x[1])[0]

{'tresseddessert': 14, 'seddes': 6, 'esseddesse': 10, 'esse': 4, 'stressdesserts': 16, 'resseddesser': 12, 'edde': 4, 'sseddess': 8}

('подчеркнутые десерты', 16)

Я использовал грубую силу, чтобы проверить, что каждая возможная подстрока является палиндромом, и обновить самую длинную найденную длину. есть более быстрые реализации на leetcode, включая динамическое программирование

import java.util.List;import java.util.ArrayList;

// этот подход работает, но есть более быстрые реализации в коде leet // может тестировать строки для палиндромов в основном методе, выводить на терминал

class Solution {

      public static void main (String [] args ) {
 
    Solution test = new Solution();
    
// can test strings for palindromes here
    System.out.println(     test.longestPalindrome( "abcdracecarabcd"   ));
    System.out.println(     test.longestPalindrome( "ottoracecar"   )); 
    System.out.println(     test.longestPalindrome( "a"   ));
    System.out.println(     test.longestPalindrome( "123otto123"   ));
    System.out.println(     test.longestPalindrome( "" ));
    System.out.println(     test.longestPalindrome( "" ));
    
}


public String longestPalindrome(String s) {
  
    List<Pair> pairs =  new ArrayList<Pair>();
    String currentHighest = "";
    
    
    // generate List of all possible subStrings (start character, and end character); there are n(n-1)/2 pair combinations.
    for (int i=0;i<=s.length();i++){
        int l = i;
        for (int j=i+1; j <= s.length(); j++) {
            int r = j;
            pairs.add(new Pair(l,r));
        }
    }
    
    
    // check if each possible substring is a palindrom and update the currentHighest found  
    for(Pair p: pairs) {
     //   System.out.println("start: " + p.L + " end: " + p.R);
        if (s.substring(p.L, p.R).equals( new StringBuffer(s.substring(p.L, p.R)).reverse().toString())) {
            if (s.substring(p.L, p.R).length() > currentHighest.length())  currentHighest = s.substring(p.L, p.R);
        }
    }
    
    return currentHighest;

}

// inner class to define a Pair
    class Pair {
        int L;
        int R;
        Pair (int l, int r){
             this.L = l;
             this.R = r;
          }
     }

}

Вот код, который вы можете использовать для поиска самой длинной палиндромной подстроки:

string = "sensmamstsihbalabhismadamsihbala"
string_shortener = ""
pres = 0
succ = 3
p_temp=0
s_temp=0
longest = ""
for i in range(len(string)-2):
    string_shortener = string[pres:succ]
    if(string_shortener==string_shortener[::-1]):
       p_temp = pres
       s_temp = succ
       for u in range(1000):
           p_temp-=1
           s_temp +=1
           string_shortener = string[p_temp:s_temp]
           if(string_shortener == string_shortener[::-1]):
                if len(string_shortener)>len(longest):
                    longest = string_shortener
            else:
                break
    pres+=1
    succ+=1
print(longest)

Я сделал имя функции как maxpalindrome(s) в этом одном строковом аргументе 's'. Эта функция вернет самую длинную подстроку палиндрома и длину подстроки...

def maxpalindrome(s):
if len(s) == 1 or s == '':
    return str(len(s)) + "\n" + s
else:
    if s == s[::-1]:
        return str(len(s)) + "\n" + s
    else:
        for i in range(len(s)-1, 0, -1):
            for j in range(len(s)-i+1):
                temp = s[j:j+i]
                if temp == temp[::-1]:
                    return str(len(temp)) +"\n"+temp
value ="Madamaaamadamaaaacdefgv"
longestPalindrome =""
lenght =0;
for i in range(len(value)):
        for j in range(0, i):
            array = value[j:i + 1]
            if (array == array[::-1] and len(longestPalindrome) < len(array)):
                longestPalindrome =array
print(longestPalindrome)
a = "xabbaabba"  # Provide any string

count=[]
for j in range(len(a)):
    for i in range(j,len(a)):
        if a[j:i+1] == a[i:j-1:-1]:      
            count.append(i+1-j)

print("Maximum size of Palindrome within String is :", max(count))

Вот еще один простой и понятный подход, взятый из отличного онлайн-курса " Дизайн компьютерных программ " П. Норвига. Он перебирает все символы в строке и пытается "увеличить" строку как влево, так и вправо.

def longest_sub_palindrome_slice(text):
    "Return (i,j) such that text[i,j] is the longest palindrome in text"
    if text == '': return (0, 0)
    def length(slice): a,b = slice; return b-a
    candidates = [grow(text, start, end)
                 for start in range(len(text))
                 for end in (start, start + 1)]
    return max(candidates, key=length)

def grow(text, start, end):
    "Start with a 0- or 1- length palindrome; try to grow a bigger one"
    while (start > 0 and end < len(text)
           and text[start-1].upper() == text[end].upper()):
        start -= 1; end += 1
    return (start, end)

Это можно определить с помощью окна, наведенного на слово.Поскольку нас интересует только поиск самого длинного палиндрома, мы можем начать размер окна с размера самого слова и постепенно уменьшать его, проверяя все возможности фрагментов. которые прикрыты окном. Мы можем остановить алгоритм, когда найдем первый кусок палиндрома, который также будет самым длинным палиндромом в данном слове.

      word = input("Word:").lower()
window_size = len(word)
found = False
while window_size > 1 and not found:
    start = 0
    while start <= len(word) - window_size and not found:
        window = word[start:start+window_size]
        if window[::-1] == window:
            print("Longest Palindrome :" , window)
            found = True
        start += 1
    window_size -= 1
inputStr = "madammmdd"
outStr = ""
uniqStr = "".join(set(inputStr))
flag = False
for key in uniqStr:
   val = inputStr.count(key)
   if val % 2 !=0:
      if not flag:
         outStr = outStr[:len(outStr)/2]+key+outStr[len(outStr)/2:]
         flag=True
      val-=1
   outStr=key*(val/2)+outStr+key*(val/2)
print outStr
def longestPalindrome(s):
        temp = ""
        for i in range(len(s)):
            for j in range(len(s)-1,i-1,-1):
                if s[i] == s[j]:
                    m = s[i:j+1]
                    if m == m[::-1]:
                        if len(temp) <= len(m):
                            temp = m
        return temp

Я должен согласиться с тем, что решение может показаться сложным, я думаю, что лучшее решение - найти самый большой палиндром в подпоследовательности (учитывая символы между ними, например, в "символе", самый большой палиндром должен быть carac):

def find_char_backwards(a, c):
for i in range(len(a) - 1, -1,-1):
    if a[i] == c:
        index=i
        return True, index

return False, 0

def longest_palindorme(a):
if len(a) < 2:
    return a
else:
    c=a[0]
    (exist_char,index) = find_char_backwards(a[1:],c)
    if exist_char:
        palindrome=[c] + longest_palindorme(a[1:index+1]) + [c]
    else:
        palindrome=[]
    rest_palidorme=longest_palindorme(a[1:])

if len(palindrome)>len(rest_palidorme):
    return palindrome
else:
    return rest_palidorme

Где a - массив, это решение использует рекурсию и динамическое программирование.

Используйте вложенный цикл:

for x in range(len(body)):
    for y in range(len(body)):
    ...
Другие вопросы по тегам