Monday, October 1, 2018

Leetcode 392. Is Subsequence

Given a string s and a string t, check if s is subsequence of t.
You may assume that there is only lower case English letters in both s and tt is potentially a very long (length ~= 500,000) string, and sis a short string (<=100).
A subsequence of a string is a new string which is formed from the original string by deleting some (can be none) of the characters without disturbing the relative positions of the remaining characters. (ie, "ace" is a subsequence of "abcde" while "aec" is not).
Example 1:
s = "abc"t = "ahbgdc"
Return true.
Example 2:
s = "axc"t = "ahbgdc"
Return false.
Follow up:
If there are lots of incoming S, say S1, S2, ... , Sk where k >= 1B, and you want to check one by one to see if T has its subsequence. In this scenario, how would you change your code?
Credits:
Special thanks to @pbrother for adding this problem and creating all test cases.

Solution:
The simplest solution is to use two pointers. If s.charAt(i) == t.charAt(j), move both of the pointers and check if i reach to the endo f s. Otherwise, just move the j pointer.


Code (Java):
class Solution {
    public boolean isSubsequence(String s, String t) {
        if (s == null || s.length() == 0) {
            return true;
        }
        
        int i = 0;
        for (int j = 0; j < t.length(); j++) {
            if (s.charAt(i) == t.charAt(j)) {
                i++;
                
                if (i == s.length()) {
                    return true;
                }
            }
        }
        
        return false;
    }
}

Followup solution:
class Solution {
    public boolean isSubsequence(String s, String t) {
        // step 1: save all the index for the t
        //
        Map<Character, List<Integer>> map = new HashMap<>();
        for (int i = 0; i < t.length(); i++) {
            char c = t.charAt(i);
            if (!map.containsKey(c)) {
                List<Integer> pos = new ArrayList<>();
                pos.add(i);
                map.put(c, pos);
            } else {
                List<Integer> pos = map.get(c);
                pos.add(i);
                map.put(c, pos);
            }
        }
        
        // step 2: for each char in s, find the first index
        //
        int prev = -1;
        for (int i = 0; i < s.length(); i++) {
            char c = s.charAt(i);
            List<Integer> pos = map.get(c);
            if (pos == null || pos.size() == 0) {
                return false;
            }
            
            int curr = getNextSmall(pos, prev);
            
            if (curr == -1) {
                return false;
            }
            
            prev = curr;
        }
        
        return true;
    }
    
    // find next number greater than target
    // if not found, return -1
    //
    private int getNextSmall(List<Integer> pos, int target) {
        int lo = 0;
        int hi = pos.size() - 1;
        
        while (lo + 1 <= hi) {
            int mid = lo + (hi - lo) / 2;
            if (pos.get(mid) == target) {
                lo = mid + 1;
            } else if (pos.get(mid) > target) {
                hi = mid;
            } else if (pos.get(mid) < target) {
                lo = mid + 1;
            }
        }
        
        if (pos.get(lo) > target) {
            return pos.get(lo);
        }
        
        if (pos.get(hi) > target) {
            return pos.get(hi);
        }
        
        return -1;
    }
}

No comments:

Post a Comment