0
public static String getMiddleString(String S, String T)
{
    if(S.length()<T.length()){
        for(int i=0;i<(T.length()-S.length());i++)S = '`'+S;
    }
    if(T.length()<S.length()){
        for(int i=0;i<(S.length()-T.length());i++)T = '`'+T;
    }

    int N = S.length();
    // Stores the base 26 digits after addition
    int[] a1 = new int[N + 1];

    for (int i = 0; i < N; i++) {
        a1[i + 1] = (int)S.charAt(i) - 97
                + (int)T.charAt(i) - 97;
    }

    // Iterate from right to left
    // and add carry to next position
    for (int i = N; i >= 1; i--) {
        a1[i - 1] += (int)a1[i] / 26;
        a1[i] %= 26;
    }

    // Reduce the number to find the middle
    // string by dividing each position by 2
    for (int i = 0; i <= N; i++) {

        // If current value is odd,
        // carry 26 to the next index value
        if ((a1[i] & 1) != 0) {

            if (i + 1 <= N) {
                a1[i + 1] += 26;
            }
        }

        a1[i] = (int)a1[i] / 2;
    }

    String result ="";
    for (int i = 1; i <= N; i++) {
        result+=(char)(a1[i] + 97);
    }
    return result;
}

This is code that I took from https://www.geeksforgeeks.org/find-the-string-present-at-the-middle-of-a-lexicographically-increasing-sequence-of-strings-from-s-to-t/ to help me find the string in the middle between 2 strings in lexicographical order (e.g. the middle string between "z" and "ad" is "ab". The idea is that it treats the strings as base-26 numbers and gets the number in the middle of them and changes it back to a string.The code from the blog only works with same length strings, so I modified it and it seems to work but I'm not exactly sure why and I'm also not sure if it would work with all cases, I would appreciate it if someone would explain why my modification is correct or incorrect.

The modification was the 2 if conditions on top, it basically prefixes the smaller string with "`" characters (ASCII=96). Initially I tried prefixing with "a", but that didn't work, so I thought of trying the character just before "a" in ASCII.

In my case when I talk about lexicographical ordering I mean: a,b,c.....y,z,aa,ab,ac,ad...zz,aaa,aab.....

Mark Rotteveel
  • 100,966
  • 191
  • 140
  • 197
  • I wouldn't even know what the middle string between `aaa` and `c` should be!? It probably works because ` is treated as -1 (https://www.asciitable.com/) in your code. But maybe `a` would be a better choice for padding. – luk2302 May 09 '23 at 17:16
  • The problem is under-specified. "Lexicographically" implies left-alignment (right padding, so "b" > "az") but the problem discussion implies, but does not explicitly specify, left-padding. Without that crucial detail, you cannot write a valid solution. – Jim Garrison May 09 '23 at 17:18
  • What you say is a lexicographical ordering is not a lexicographical ordering. – Mark Rotteveel May 10 '23 at 15:49
  • @MarkRotteveel Someone pointed that out and so I explained what I meant in the edit. What do you suggest calling this type of ordering? – Mohamed Shereef May 10 '23 at 18:03
  • I'm not sure this ordering has an explicit name. – Mark Rotteveel May 11 '23 at 08:14

1 Answers1

2

This sample code implements your example in a concise manner.

The function alpha_string_to_number takes a std::string of lower case alpha and converts it into a number using the assignments a=1, b=2, etc. This is not base-26, but similar. The function number_to_alpha_string does the inverse.

As far as I can tell, this is a valid lexicographical ordering in that a is 1, b is 2, aa is 27, ab is 28 etc.

For z you get 26 and for ad you get 30, the average of which is 28 or ab. Now, in what sense this is the "middle" between z and ad is up for debate, but it matches your example.

You should be able to use the following to help debug your function.

Sample Code

#include <iostream>

size_t alpha_string_to_number(const std::string& str) {
    size_t n{}, place_digit{1};
    for (auto elem : str) {
        n *= 26;
        n += 1 + (elem - 'a');
    }
    return n;
}

std::string number_to_alpha_string(size_t n) {
    std::string r{};
    while (n > 0) {
        r += 'a' + (--n % 26);
        n /= 26;
    }
    std::reverse(r.begin(), r.end());
    return r;
}

int main(int argc, const char *argv[]) {

    auto n1 = alpha_string_to_number("z");
    auto n2 = alpha_string_to_number("ad");
    std::cout << n1 << std::endl;
    std::cout << n2 << std::endl;
    std::cout << number_to_alpha_string((n1 + n2) / 2) << std::endl;
    return 0;
}

Extended Explanation

alpha_string_to_number keeps track of the result in n and value of the current digit in place_digit. For base-10, place digit would cycle through the powers of ten, so 1, 10, 100, 1000, etc. For this example we have 26 characters so place digit is 1, 26, 26^2, 26^3, etc. This allows us to shift the previous n over a single place digit each time through loop as we add in the value of the current character.

Note that the character values range from 1 to 26 (instead of 0 to 25) in order to make the lexicographical ordering work correctly. Hence, the +1 when converting to a number and the -1 when converting from a number.

number_to_alpha_string keeps track of the result string r which is computed in reverse order since it is easier to extract the least significant remaining digit each time through the loop rather than the most significant. Before returning, we reverse the characters to put them in the correct order.

RandomBits
  • 4,194
  • 1
  • 17
  • 30
  • Your code works wonderfully and it actually solved my problem. Im trying to understand how the alpha_string_to_number function and its inverse works though. It seems simple but I just can't quite get it. So if you care to explain the idea behind them I would really appreciate that. – Mohamed Shereef May 09 '23 at 20:16
  • I also just realized the alpha_string_to_number when given "aaa" outputs 18253 and not 703. – Mohamed Shereef May 10 '23 at 02:21
  • You are correct -- there was a bug in `alpha_string_to_number`. I fixed the code.in the post. Now `aaa` produces `703`. That's probably why it was hard to understand. It worked for 1 or 2 characters, but failed for anything longer. – RandomBits May 10 '23 at 03:14
  • 1
    if you change `r += 'a' + (--n % 26);` to `r = ('a' + (--n % 26)) + r;` you shouldn't have to reverse it. – WJS May 10 '23 at 13:47
  • 1
    @WJS True, but at the cost of extra computation assuming a typical string implementation. Appending to create a string then reversing it takes O(N) operations while prepending as you go is O(n log n). – RandomBits May 10 '23 at 15:29