Long Pressed Name, by Leetcode

Problem: https://leetcode.com/problems/long-pressed-name/description/

Your friend is typing his name into a keyboard.  Sometimes, when typing a character c, the key might get long pressed, and the character will be typed 1 or more times.
You examine the typed characters of the keyboard.  Return True if it is possible that it was your friends name, with some characters (possibly none) being long pressed.
Recursive solution, with simple base case, trimming based on the first chars equality (or inequality), optimization based on the typed string containing the name, and finally the recursion moving name once or keeping it as it is. Key optimization that made it pass was this. Cheers, Marcelo

public class Solution
{
public bool IsLongPressedName(string name, string typed)
{
if (String.IsNullOrEmpty(name) && String.IsNullOrEmpty(typed)) return true;
if (String.IsNullOrEmpty(name) || String.IsNullOrEmpty(typed)) return false;
if (name[0] != typed[0]) return false;
if (typed.Contains(name)) return true;
return IsLongPressedName(name, typed.Substring(1)) || 
                                   IsLongPressedName(name.Substring(1), typed.Substring(1));
}
}

Comments

  1. Very concise solution, Marcelo! The complexity can be improved though, since your solution has a lot of overlapping problems and is somewhat similar to a naive implementation of wildcard matching problem. In this particular case though, a single scan of both strings is enough. We can use 2 indices pointing at positions inside of name and typed - if characters these indices point to are not the same, we can immediately tell that it's not a result of a long press, but if they are, we can count how many repetitions we have for each and the typed string can only be a result of a long press if this number is <= in name string. The implementation of this idea in C++ is somewhat longer but hopefully still easy to follow is below:

    class Solution {
    public:
    bool isLongPressedName(const string& name, const string& typed) {
    if (name.empty() != typed.empty()) return false;
    if (name.empty() && typed.empty()) return true;
    int right = 0;
    for (int i = 0; i < name.size(); ) {
    if (name[i] != typed[right]) return false;
    int name_count = 1;
    int j;
    for (j = i + 1; j < name.size() && name[j-1] == name[j]; ++j) {
    name_count += 1;
    }
    i = j;
    int typed_count = 1;
    for (j = right + 1; j < typed.size() && typed[j-1] == typed[j]; ++j) {
    typed_count += 1;
    }
    right = j;
    if (name_count > typed_count) return false;
    }
    return true;
    }
    };

    ReplyDelete
  2. So true, after I wrote it I realized that my solution is actually exponential and I thought exactly about yours. Very nice!!

    ReplyDelete
    Replies
    1. well, as long as it's accepted it's legit :) It's always best to start with an obviously correct solution and if necessary optimize it and your solution is definitely more readable, although I believe the iterative solution could be significantly improved by using missing abstractions like takeWhile from Haskell. In any case it's always great to compare solutions with yours, so please keep them coming :)

      Delete

Post a Comment

Popular posts from this blog

Advent of Code - Day 6, 2024: BFS and FSM

Golang vs. C#: performance characteristics (simple case study)

Advent of Code - Day 7, 2024: Backtracking and Eval