4

I wrote the following code to find the first capital letter in a string using binary search:

char first_capital(const char str[], int n)
{
    int begin = 0;
    int end = n - 1;
    int mid;
    while (begin <= end)
    {
        mid = (begin + end) / 2;
        if (mid == 0 && isupper(str[mid]))
        {
            return mid;
        }
        else if (mid > 0 && isupper(str[mid]) && islower(str[mid - 1]))
        {
            return mid;
        }
        if (islower(str[mid]))
        {
            begin = mid + 1;
        }
        else
        {
            end = mid - 1;
        }
    }
    return 0;
}

Currently my code isn't working as expected while testing it. If anyone can mention where I went wrong it would help a lot.

NOTE: The input string will be already sorted (all lower case letters appear before upper case letters). const char str[] is the string and int n is the length of the string.

EDIT: for example: first_capital("abcBC", 5) should return 'B'.

chqrlie
  • 131,814
  • 10
  • 121
  • 189
Jason
  • 85
  • 5
  • https://www.geeksforgeeks.org/binary-search-a-string/ – Robert Harvey Mar 02 '21 at 18:00
  • 2
    Your proposed sort isn't going to work; *capital letters precede lower case letters* on the [ASCII code chart](https://www.commfront.com/pages/ascii-chart). – Robert Harvey Mar 02 '21 at 18:02
  • @Jason What does this return statement return 0; mean? – Vlad from Moscow Mar 02 '21 at 18:06
  • @Jason you are returning the position of the character found and not the char itself. This index is then converted into char due to the return type and will never yield expected result. Try replacing `return mid` with `return str[mid]` – lastbreath Mar 02 '21 at 18:06
  • 1
    @ggorlen "abcABB" output: A, wont be aAbBBc, would be abcABB – Jason Mar 02 '21 at 18:06
  • if there's no upper case letter in the string, return 0 @VladfromMoscow – Jason Mar 02 '21 at 18:08
  • @Jason And if the string contains only upper case letters what does the function return? – Vlad from Moscow Mar 02 '21 at 18:09
  • @VladfromMoscow the first upper case letter – Jason Mar 02 '21 at 18:09
  • If `mid` points to an upper case letter there could still be other upper case letters to the left of it, so you'll still have to do further search in `0..mid-1`. – 500 - Internal Server Error Mar 02 '21 at 18:11
  • Maybe this will work? https://en.cppreference.com/w/cpp/algorithm/lower_bound (as an algorithm, you'd have to convert it to C.) – Neil Mar 02 '21 at 18:15
  • @Neil wrong language. C not C++ here – ggorlen Mar 02 '21 at 18:17
  • 2
    You're returning `mid`, not `str[mid]`. – Perette Mar 02 '21 at 18:23
  • It is difficult to offer solutions when the problem statement is simply, ["it doesn't work"](http://idownvotedbecau.se/itsnotworking/). Please [edit] your question to give a more complete description of what you expected to happen and how that differs from the actual results. See [ask] for hints on what makes a good explanation. – Toby Speight Mar 02 '21 at 21:20

3 Answers3

5

Your logic is completely right, but you returned the wrong value

char first_capital(const char str[], int n)
{
    int begin = 0;
    int end = n - 1;
    int mid;
    while (begin <= end)
    {
        mid = (begin + end) / 2;
        if(mid == 0 && isupper(str[mid]))
        {
            return mid;    // Here the index is returned not the character
        }
        else if (mid > 0 && isupper(str[mid]) && islower(str[mid-1]))
        {
            return mid;    // Same goes here
        }
        if(islower(str[mid]))
        {
            begin = mid+1;
        }
        else
        {
            end = mid - 1;
        }
    }
    return 0;
}

The driver code

int main(){
    
    printf("%d\n", first_capital("abcabcabcabcabcZ", 16));
}

will be giving 15 as an answer which is the index of the character Z.

if u want the character to be returned replace return mid with return str[mid] and 'Z' will be returned.

lastbreath
  • 383
  • 1
  • 11
3
#include <stdio.h>

/* This will find and return the first UPPERCASE character in txt
 * provided that txt is zero-or-more lowercase letters,
 * followed by zero-or-more uppercase letters.
 * If it is all lower-case letters, it will return \0 (end of string)
 * If it is all upper-case letters, it will return the first letter (txt[0])
 * If there are non-alpha characters in the string, all bets are off.
 */
char findFirstUpper(const char* txt)
{
    size_t lo = 0;
    size_t hi = strlen(txt);
    
    while(hi-lo > 1)
    {
        size_t mid = lo + (hi-lo)/2;
        *(isupper(txt[mid])? &hi : &lo) = mid;
    }
    
    return isupper(txt[lo])? txt[lo] : txt[hi];
}

int main(void)
{
    char answer = findFirstUpper("abcBC");
    printf("Found char %c\n", answer);
    return 0;
}
abelenky
  • 63,815
  • 23
  • 109
  • 159
  • 1
    I approved the edit by ani1998ket out of a sense of perfection. Although I think it makes the code slightly less readable for a beginner, it does prevent a rare type of bug. – abelenky Mar 02 '21 at 18:37
  • 1
    and that's why i didn't do the same correction is Jason's code :) – lastbreath Mar 02 '21 at 18:38
0

If the function deals with strings then the second parameter should be removed.

The function should return a pointer to the first upper case letter or a null pointer if such a letter is not present in the string. That is the function declaration and behavior should be similar to the declaration and behavior of the standard string function strchr. The only difference is that your function does not require a second parameter of the type char because the searched character is implicitly defined by the condition to be an upper case character.

On the other hand, though your function has the return type char it returns an integer that specifies the position of the found character. Also your function does not make a difference between the situations when an upper case character is not found and when a string contains an upper case character in its first position.

Also your function has too many if-else statements.

The function can be declared and defined the following way as it is shown in the demonstrative program below.

#include <stdio.h>
#include <string.h>
#include <ctype.h>

char * first_capital( const char s[] )
{
    const char *first = s;
    const char *last = s + strlen( s );
    
    while ( first < last )
    {
        const char *middle = first + ( last - first ) / 2;
        
        if ( islower( ( unsigned char )*middle ) )
        {
            first = middle + 1;
        }
        else
        {
            last = middle;
        }
    }
    
    return ( char * )( isupper( ( unsigned char )*first ) ? first : NULL );
}

int main(void) 
{
    const char *s = "";
    
    char *result = first_capital( s );
    
    if ( result )
    {
        printf( "%c at %zu\n", *result, ( size_t )( result - s ) );
    }
    else
    {
        printf( "The string \"%s\" does not contain an upper case letter.\n", s );
    }
    
    s = "a";
    
    result = first_capital( s );

    if ( result )
    {
        printf( "%c at %zu\n", *result, ( size_t )( result - s ) );
    }
    else
    {
        printf( "The string \"%s\" does not contain an upper case letter.\n", s );
    }
    
    s = "A";
    
    result = first_capital( s );

    if ( result )
    {
        printf( "%c at %zu\n", *result, ( size_t )( result - s ) );
    }
    else
    {
        printf( "The string \"%s\" does not contain an upper case letter.\n", s );
    }
    
    s = "abcdefA";
    
    result = first_capital( s );

    if ( result )
    {
        printf( "%c at %zu\n", *result, ( size_t )( result - s ) );
    }
    else
    {
        printf( "The string \"%s\" does not contain an upper case letter.\n", s );
    }
    
    s = "abAB";
    
    result = first_capital( s );

    if ( result )
    {
        printf( "%c at %zu\n", *result, ( size_t )( result - s ) );
    }
    else
    {
        printf( "The string \"%s\" does not contain an upper case letter.\n", s );
    }
    
    return 0;
}

The program output is

The string "" does not contain an upper case letter.
The string "a" does not contain an upper case letter.
A at 0
A at 6
A at 2
Vlad from Moscow
  • 301,070
  • 26
  • 186
  • 335