792. 匹配子序列的单词数

Given string S and a dictionary of words words, find the number of words[i] that is a subsequence of S.

Example :
Input: 
S = "abcde"
words = ["a", "bb", "acd", "ace"]
Output: 3
Explanation: There are three words in words that are a subsequence of S: "a", "acd", "ace".

Note:

  • All words in words and S will only consists of lowercase letters.
  • The length of S will be in the range of [1, 50000].
  • The length of words will be in the range of [1, 5000].
  • The length of words[i] will be in the range of [1, 50].

=====================================================================

Ideas : There can be no violent solution to this problem.We can use caching,and some details of optimization

=====================================================================

brute force : 

    public int numMatchingSubseq(String S, String[] words) {
        int res=0;
        for (String str:words) {
            int p = 0;
            int size = str.length()-1;
            for (int i = 0; p!=size&&i < S.length(); i++) {
                if (S.charAt(i)==str.charAt(p)) p++;
            }
            if (size==p) res++;
        }
        return res;
    }

A bad solution :

    public int numMatchingSubseq(String S, String[] words) {
        int res = 0;
        List<List<Integer>> dict = new ArrayList<>();
        for (int i = 0; i < 26; i++) {
            dict.add(new ArrayList<>());
        }
        for (int i = 0; i < S.length(); i++) {
            char aim  = S.charAt(i);
            dict.get(aim-97).add(i);
        }
        a:for (String str : words) {
            for (int i = 0,p = -1; i < str.length(); i++) {
                char aim = str.charAt(i);
                List<Integer> list = dict.get(aim - 97);
                if (list.size()==0||list.get(list.size()-1)<=p) continue a;
                for (int j = 0; j < list.size(); j++) {
                    if (list.get(j)>p){
                        p=list.get(j);
                        break ;
                    }
                }
            }
            res++;
        }
        return res;
    }

Add cache optimization : 

    public int numMatchingSubseq(String S, String[] words) {
        int res = 0;
        Map<String, Boolean> map = new HashMap<>();
        Node[] nodes = new Node[26];
        for (int i = 0; i < S.length(); i++) {
            int zmidx = S.charAt(i)-97;
            if (nodes[zmidx]==null) nodes[zmidx] = new Node();
            nodes[zmidx].ids.add(i);
        }
        for(int i = 0; i < words.length; i++) {
            if (map.containsKey(words[i])) {
                if (map.get(words[i]))
                    res++;
            }
            else if (check(nodes,S, words[i])) {
                res++;
                map.put(words[i], true);
            } else {
                map.put(words[i], false);
            }
        }
        return res;
    }
    private boolean check(Node[] nodes,String str,String word){
        if (str.length()<word.length()) return false;
        int p = -1;
        for (int i = 0; i < word.length(); i++) {
            int index = word.charAt(i)-97;
            if (nodes[index]==null||nodes[index].ids.get(nodes[index].ids.size()-1)<=p) return false;
            for (int x:nodes[index].ids) {
                if (x>p){
                    p=x;
                    break;
                }
            }
        }
        return true;
    }
    class Node{
        List<Integer> ids = new ArrayList<>();
    }

I can't accept that the above method doesn't run very fast , until I saw the test case .

There are too many extreme situations in test cases , causing some abnormal solutions to become fast

such as String.indexOf() 

public int numMatchingSubseq(String S, String[] words) {
        HashMap<String, Integer> map = new HashMap<>();
        int index = 0, count = 0;
        boolean sub;
        for (String word : words) {
            if (map.containsKey(word)) {
                count += map.get(word);
            } else {
                index = -1;
                sub = true;
                for (int i = 0; i < word.length(); i++) {
                    index = S.indexOf(word.charAt(i), index + 1);
                    if (index < 0) {
                        sub = false;
                        break;
                    }
                }
                if (sub) {
                    count++;
                    map.put(word, 1);
                } else {
                    map.put(word, 0);
                }
            }
        }
        return count;
    }

猜你喜欢

转载自blog.csdn.net/start_lie/article/details/85072650