Compare strings with backspace!

844. Compare strings with backspace

Link to force buckle topic: https://leetcode-cn.com/problems/backspace-string-compare

Given two strings S and T, when they are input into a blank text editor respectively, judge whether they are equal and return the result# Represents a backspace character.

Note: if you enter a backspace character for empty text, the text continues to be empty.

Example 1:

  • Input: S = "ab#c", T = "ad#c"
  • Output: true
  • Explanation: both S and T will become "ac".

Example 2:

  • Input: S = "ab##", T = "c#d#"
  • Output: true
  • Explanation: both S and T will become "".

Example 3:

  • Input: S = "a##c", t = "a#a#c"
  • Output: true
  • Explanation: both S and T will become "c".

Example 4:

  • Input: S = "a#c", T = "b"
  • Output: false
  • Explanation: S will become "c", but T is still "b".

thinking

This paper will give a stack simulation method with spatial complexity O(n) and a double pointer method with spatial complexity O(1).

Common method (idea of using stack)

This topic is to use the rhythm of the stack. This matching (elimination) problem is also what the stack is good at. The students who brush the questions together should know that Stack and queue: matching is the strength of stack , I've already mentioned using the stack to do similar things once.

Well, the idea of stack can be used for this problem, but it is not necessary to use stack, because it is a little troublesome to compare the elements in the stack at the last comparison.

Here, the string is directly used as the stack. The string is added and popped at the end. The string has corresponding interfaces. Finally, when comparing, just compare two strings, which is more convenient than comparing the elements in the stack.

The code is as follows:

class Solution {
public:
    bool backspaceCompare(string S, string T) {
        string s; // When the stack is used
        string t; // When the stack is used
        for (int i = 0; i < S.size(); i++) {
            if (S[i] != '#') s += S[i];
            else if (!s.empty()) {
                s.pop_back();

        }
        for (int i = 0; i < T.size(); i++) {
            if (T[i] != '#') t += T[i];
            else if (!t.empty()) {
                t.pop_back();
            }
        }
        if (s == t) return true; // It is much more convenient to directly compare whether two strings are equal than using stack
        return false;
    }
};
  • Time complexity:

O(n + m), n is the length of S and M is the length of T, which can also be understood as the time complexity of O(n)

  • Space complexity:

O(n + m) of course, in the above code, you can find that there are repeated logic processing S and processing T. you can separate this common logic. The code is simplified as follows:

class Solution {
private:
string getString(const string& S) {
    string s;
    for (int i = 0; i < S.size(); i++) {
        if (S[i] != '#') s += S[i];
        else if (!s.empty()) {
            s.pop_back();
        }
    }
    return s;
}
public:
    bool backspaceCompare(string S, string T) {
        return getString(S) == getString(T);
    }
};

Performance remains:

  • Time complexity: O(n + m)
  • Spatial complexity: O(n + m)

Optimization method (double pointer from back to front)

Of course, the spatial complexity of O(1) can also be used to solve this problem.

At the same time, traverse s and T from back to front (initial I is the end of S, initial j is the end of T), record the number of # and simulate the elimination operation. If # used up, start comparing S[i] and S[j].

The animation is as follows:

If S[i] and S[j] are different, false is returned. If a pointer (I or j) goes to the head of the string first, false is also returned.

The code is as follows:

class Solution {
public:
    bool backspaceCompare(string S, string T) {
        int sSkipNum = 0; // Record the # quantity of S
        int tSkipNum = 0; // Record the # quantity of T
        int i = S.size() - 1;
        int j = T.size() - 1;
        while (1) {
            while (i >= 0) { // From back to front, eliminate S#
                if (S[i] == '#') sSkipNum++;
                else {
                    if (sSkipNum > 0) sSkipNum--;
                    else break;
                }
                i--;
            }
            while (j >= 0) { // From back to front, eliminate the of T#
                if (T[j] == '#') tSkipNum++;
                else {
                    if (tSkipNum > 0) tSkipNum--;
                    else break;
                }
                j--;
            }
            // The latter part # is eliminated. Next, compare s [i]= T[j]
            if (i < 0 || j < 0) break; // S or T traverses to the end
            if (S[i] != T[j]) return false;
            i--;j--;
        }
        // Description: S and T are traversed at the same time
        if (i == -1 && j == -1) return true;
        return false;
    }
};
  • Time complexity: O(n + m)
  • Space complexity: O(1)

Other language versions

Java:

// Common method (idea of using stack)
class Solution {
    public boolean backspaceCompare(String s, String t) {
        StringBuilder ssb = new StringBuilder(); // Simulation stack
        StringBuilder tsb = new StringBuilder(); // Simulation stack
        // Process two strings separately
        for (char c : s.toCharArray()) {
            if (c != '#') {
                ssb.append(c); // Simulation stack
            } else if (ssb.length() > 0){ // You can only play the stack if the stack is not empty
                ssb.deleteCharAt(ssb.length() - 1); // Simulated bomb stack
            }
        }
        for (char c : t.toCharArray()) {
            if (c != '#') {
                tsb.append(c); // Simulation stack
            } else if (tsb.length() > 0){ // You can only play the stack if the stack is not empty
                tsb.deleteCharAt(tsb.length() - 1); // Simulated bomb stack
            }
        }
        return ssb.toString().equals(tsb.toString());
    }
}

python

class Solution:

    def get_string(self, s: str) -> str :
        bz = []
        for i in range(len(s)) :
            c = s[i]
            if c != '#' :
                bz.append(c) # Simulation stack
            elif len(bz) > 0: # You can only play the stack if the stack is not empty
                bz.pop() # Simulated bomb stack
        return str(bz)

    def backspaceCompare(self, s: str, t: str) -> bool:
        return self.get_string(s) == self.get_string(t)
        pass

Go

func getString(s string) string {
 bz := []rune{}
 for _, c := range s {
  if c != '#' {
   bz = append(bz, c); // Simulation stack
  } else if len(bz) > 0 { // You can only play the stack if the stack is not empty
   bz = bz[:len(bz)-1] // Simulated bomb stack
  }
 }
 return string(bz)
}

func backspaceCompare(s string, t string) bool {
 return getString(s) == getString(t)
}

JavaScript

// Double stack
var backspaceCompare = function(s, t) {
    const arrS = [], arrT = []; // Arrays are used as stacks
    for(let char of s){
        char === '#' ? arrS.pop() : arrS.push(char);
    }
    for(let char of t){
        char === '#' ? arrT.pop() : arrT.push(char);
    }
    return arrS.join('') === arrT.join(''); // Compare two strings for equality
};

//Dual stack reduction
var backspaceCompare = function(s, t) {
    const getString = s => {
        let arrS = [];
        for(let char of s){
            char === '#' ? arrS.pop() : arrS.push(char);
        }
        return arrS.join('');
    }
    return getString(s) === getString(t);
};

//Double pointer
var backspaceCompare = function(s, t) {
    let sSkipNum = 0; // Record the # number of s
    let tSkipNum = 0; // Record the # quantity of t
    let i = s.length - 1, j = t.length - 1;
    while(true) {
        while(i >= 0){ // From back to front, eliminate s#
            if(s[i] === '#') sSkipNum++;
            else {
                if (sSkipNum > 0) sSkipNum--;
                else break;
            }
            i--;
        }
        while (j >= 0) { // From back to front, eliminate the of t#
            if (t[j] === '#') tSkipNum++;
            else {
                if (tSkipNum > 0) tSkipNum--;
                else break;
            }
            j--;
        }
        // The latter part # is eliminated. Next, compare s [i]= t[j]
        if (i < 0 || j < 0) break; // s or t traverses to the end
        if (s[i] !== t[j]) return false;
        i--;j--;
    }
    // Description: s and t are traversed at the same time
    if (i == -1 && j == -1) return true;
    return false;
};

Added by gynophobia on Wed, 29 Dec 2021 04:29:15 +0200