-1

This is my current approach:

def isPalindrome(s):
    if (s[::-1] == s):
        return True
    return False

def solve(s):
    l = len(s)
    ans = ""
    
    for i in range(l):
        subStr = s[i]
        for j in range(i + 1, l):
            subStr += s[j]
            if (j - i + 1 <= len(ans)):
                continue
            if (isPalindrome(subStr)):
                ans = max(ans, subStr, key=len)

    return ans if len(ans) > 1 else s[0]

print(solve(input()))

My code exceeds the time limit according to the auto scoring system. I've already spend some time to look up on Google, all of the solutions i found have the same idea with no optimization or using dynamic programming, but sadly i must and only use brute force to solve this problem. I was trying to break the loop earlier by skipping all the substrings that are shorter than the last found longest palindromic string, but still end up failing to meet the time requirement. Is there any other way to break these loops earlier or more time-efficient approach than the above?

Duong Pham
  • 11
  • 3
  • 2
    "sadly i must and only use brute force to solve this problem" - why so? – Phenomenal One Apr 26 '21 at 06:54
  • Class assignment requires students to use only brute force. – Duong Pham Apr 26 '21 at 06:57
  • A class assignment requires brute force? The only way this could make sense to me is if they are trying to demonstrate that brute force won't always be fast enough, and some upcoming question asks you to find a non-brute-force approach that always finishes in time. – j_random_hacker Apr 26 '21 at 07:23
  • 1
    where is @blhsing answer? its only drawback was that it didn't handle even palindrome... – TUI lover Apr 26 '21 at 07:55
  • i've already tried @blhsing approach, it's kinda like the idea on [gfg](https://www.geeksforgeeks.org/longest-palindrome-substring-set-1/). Not making any significant improvements. – Duong Pham Apr 26 '21 at 07:56
  • @DuongPham Read about Expand Around Center approach for solving this problem. I believe that's what you are looking for! – Phenomenal One Apr 26 '21 at 07:58
  • @j_random_hacker this problem's test cases is designed and supposed to be solved with optimal brute force solution, guaranteed by my mentor. – Duong Pham Apr 26 '21 at 08:01
  • 1
    @DuongPham The brute-force approach on GFG costs *O(n^3)* because it repeats comparisons of the inner substrings, which my solution does not. With two nested loops my solution costs *O(n^2)* instead. I did fix my solution for even-length palindromes by the way. – blhsing Apr 26 '21 at 09:39

6 Answers6

1

With subStr += s[j], a new string is created over the length of the previous subStr. And with s[::-1], the substring from the previous offset j is copied over and over again. Both are inefficient because strings are immutable in Python and have to be copied as a new string for any string operation. On top of that, the string comparison in s[::-1] == s is also inefficient because you've already compared all of the inner substrings in the previous iterations and need to compare only the outermost two characters at the current offset.

You can instead keep track of just the index and the offset of the longest palindrome so far, and only slice the string upon return. To account for palindromes of both odd and even lengths, you can either increase the index by 0.5 at a time, or double the length to avoid having to deal with float-to-int conversions:

def solve(s):
    length = len(s) * 2
    index_longest = offset_longest = 0
    for index in range(length):
        offset = 0
        for offset in range(1 + index % 2, min(index, length - index), 2):
            if s[(index - offset) // 2] != s[(index + offset) // 2]:
                offset -= 2
                break
        if offset > offset_longest:
            index_longest = index
            offset_longest = offset
    return s[(index_longest - offset_longest) // 2: (index_longest + offset_longest) // 2 + 1]
blhsing
  • 91,368
  • 6
  • 71
  • 106
0

This modification of your code should improve performance. You can stop your code when the max possible substring is smaller than your already computed answer. Also, you should start your second loop with j+ans+1 instead of j+1 to avoid useless iterations :

def solve(s):
    l = len(s)
    ans = ""
    
    for i in range(l):
        if (l-i+1 <= len(ans)):
            break
        subStr = s[i:len(ans)]
        for j in range(i + len(ans) + 1, l+1):
            if (isPalindrome(subStr)):
                ans = subStr
            subStr += s[j]
    return ans if len(ans) > 1 else s[0]
TUI lover
  • 542
  • 4
  • 16
0

Solved by using the approach "Expand Around Center", thanks @Maruthi Adithya

Duong Pham
  • 11
  • 3
0

This is a solution that has a time complexity greater than the solutions provided.

Note: This post is to think about the problem better and does not specifically answer the question. I have taken a mathematical approach to find a time complexity greater than 2^L (where L is size of input string)

Note: This is a post to discuss potential algorithms. You will not find the answer here. And the logic shown here has not been proven extensively. Do let me know if there is something that I haven't considered.

Approach: Create set of possible substrings. Compare and find the maximum pair* from this set that has the highest possible pallindrome.

Example case with input string: "abc".

In this example, substring set has: "a","b","c","ab","ac","bc","abc".

  • 7 elements.

Comparing each element with all other elements will involve: 7^2 = 49 calculations.

Hence, input size is 3 & no of calculations is 49.

Time Complexity:

First compute time complexity for generating the substring set:

<a href="https://www.codecogs.com/eqnedit.php?latex=\sum_{a=1}^{L}\left&space;(&space;C_{a}^{L}&space;\right&space;)" target="_blank"><img src="https://latex.codecogs.com/gif.latex?\sum_{a=1}^{L}\left&space;(&space;C_{a}^{L}&space;\right&space;)" title="\sum_{a=1}^{L}\left ( C_{a}^{L} \right )" /></a>

(The math equation is shown in the code snippet)

Here, we are adding all the different substring size combination from the input size L.

To make it clear: In the above example input size is 3. So we find all the pairs with size =1 (i.e: "a","b","c"). Then size =2 (i.e: "ab","ac","bc") and finally size = 3 (i.e: "abc").

  1. So choosing 1 character from input string = combination of taking L things 1 at a time without repetition. In our case number of combinations = 3. This can be mathematically shown as (where a = 1):

<a href="https://www.codecogs.com/eqnedit.php?latex=C_{a}^{L}" target="_blank"><img src="https://latex.codecogs.com/gif.latex?C_{a}^{L}" title="C_{a}^{L}" /></a>
  1. Similarly choosing 2 char from input string = 3
  2. Choosing 3 char from input string = 1

Finding time complexity of palindrome pair from generated set with maximum length: Size of generated set: N For this we have to compare each string in set with all other strings in set.

So N*N, or 2 for loops. Hence the final time complexity is:

<a href="https://www.codecogs.com/eqnedit.php?latex=\sum_{a=1}^{L}\left&space;(&space;C_{a}^{L}&space;\right&space;)^{2}" target="_blank"><img src="https://latex.codecogs.com/gif.latex?\sum_{a=1}^{L}\left&space;(&space;C_{a}^{L}&space;\right&space;)^{2}" title="\sum_{a=1}^{L}\left ( C_{a}^{L} \right )^{2}" /></a>

This is diverging function greater than 2^L for L > 1.

However, there can be multiple optimizations applied to this. For example: there is no need to compare "a" with "abc" as "a" will also be compared with "a". Even if this optimization is applied, it will still have a time complexity > 2^L (For the most cases).

Hope this gave you a new perspective to the problem.

PS: This is my first post.

-1

You should not find the string start from the beginning of that string, but you should start from the middle of it & expand the current string

For example, for the string xyzabccbalmn, your solution will cost ~ 6 * 11 comparison but searching from the middle will cost ~ 11 * 2 + 2 operations

But anyhow, brute-forcing will never ensure that your solution will run fast enough for any arbitrary string.

-2

Try this:

def solve(s):
    if len(s)==1:
        print(0)
        return '1'
    if len(s)<=2 and not(isPalindrome(s)):
        print (0)
        return '1'
    elif isPalindrome(s):
        print( len(s))
        return '1'
    elif isPalindrome(s[0:len(s)-1]) or  isPalindrome(s[1:len(s)]):
          print (len(s)-1)
          return '1'
    elif  len(s)>=2:      
         solve(s[0:len(s)-1])
         return '1'
    return 0
Nir Elbaz
  • 556
  • 4
  • 19