Welcome to Subscribe On Youtube

3292. Minimum Number of Valid Strings to Form Target II

Description

You are given an array of strings words and a string target.

A string x is called valid if x is a prefix of any string in words.

Return the minimum number of valid strings that can be concatenated to form target. If it is not possible to form target, return -1.

 

Example 1:

Input: words = ["abc","aaaaa","bcdef"], target = "aabcdabc"

Output: 3

Explanation:

The target string can be formed by concatenating:

  • Prefix of length 2 of words[1], i.e. "aa".
  • Prefix of length 3 of words[2], i.e. "bcd".
  • Prefix of length 3 of words[0], i.e. "abc".

Example 2:

Input: words = ["abababab","ab"], target = "ababaababa"

Output: 2

Explanation:

The target string can be formed by concatenating:

  • Prefix of length 5 of words[0], i.e. "ababa".
  • Prefix of length 5 of words[0], i.e. "ababa".

Example 3:

Input: words = ["abcdef"], target = "xyz"

Output: -1

 

Constraints:

  • 1 <= words.length <= 100
  • 1 <= words[i].length <= 5 * 104
  • The input is generated such that sum(words[i].length) <= 105.
  • words[i] consists only of lowercase English letters.
  • 1 <= target.length <= 5 * 104
  • target consists only of lowercase English letters.

Solutions

Solution 1

  • class Hashing {
        private final long[] p;
        private final long[] h;
        private final long mod;
    
        public Hashing(String word, long base, int mod) {
            int n = word.length();
            p = new long[n + 1];
            h = new long[n + 1];
            p[0] = 1;
            this.mod = mod;
            for (int i = 1; i <= n; i++) {
                p[i] = p[i - 1] * base % mod;
                h[i] = (h[i - 1] * base + word.charAt(i - 1)) % mod;
            }
        }
    
        public long query(int l, int r) {
            return (h[r] - h[l - 1] * p[r - l + 1] % mod + mod) % mod;
        }
    }
    
    class Solution {
        private Hashing hashing;
        private Set<Long>[] s;
    
        public int minValidStrings(String[] words, String target) {
            int base = 13331, mod = 998244353;
            hashing = new Hashing(target, base, mod);
            int m = Arrays.stream(words).mapToInt(String::length).max().orElse(0);
            s = new Set[m + 1];
            Arrays.setAll(s, k -> new HashSet<>());
            for (String w : words) {
                long h = 0;
                for (int j = 0; j < w.length(); j++) {
                    h = (h * base + w.charAt(j)) % mod;
                    s[j + 1].add(h);
                }
            }
    
            int ans = 0;
            int last = 0;
            int mx = 0;
            int n = target.length();
            for (int i = 0; i < n; i++) {
                int dist = f(i, n, m);
                mx = Math.max(mx, i + dist);
                if (i == last) {
                    if (i == mx) {
                        return -1;
                    }
                    last = mx;
                    ans++;
                }
            }
            return ans;
        }
    
        private int f(int i, int n, int m) {
            int l = 0, r = Math.min(n - i, m);
            while (l < r) {
                int mid = (l + r + 1) >> 1;
                long sub = hashing.query(i + 1, i + mid);
                if (s[mid].contains(sub)) {
                    l = mid;
                } else {
                    r = mid - 1;
                }
            }
            return l;
        }
    }
    
    
  • class Hashing {
    private:
        vector<long long> p;
        vector<long long> h;
        long long mod;
    
    public:
        Hashing(const string& word, long long base, int mod) {
            int n = word.size();
            p.resize(n + 1);
            h.resize(n + 1);
            p[0] = 1;
            this->mod = mod;
            for (int i = 1; i <= n; i++) {
                p[i] = (p[i - 1] * base) % mod;
                h[i] = (h[i - 1] * base + word[i - 1]) % mod;
            }
        }
    
        long long query(int l, int r) {
            return (h[r] - h[l - 1] * p[r - l + 1] % mod + mod) % mod;
        }
    };
    
    class Solution {
    public:
        int minValidStrings(vector<string>& words, string target) {
            int base = 13331, mod = 998244353;
            Hashing hashing(target, base, mod);
            int m = 0, n = target.size();
            for (const string& word : words) {
                m = max(m, (int) word.size());
            }
    
            vector<unordered_set<long long>> s(m + 1);
            for (const string& w : words) {
                long long h = 0;
                for (int j = 0; j < w.size(); j++) {
                    h = (h * base + w[j]) % mod;
                    s[j + 1].insert(h);
                }
            }
    
            auto f = [&](int i) -> int {
                int l = 0, r = min(n - i, m);
                while (l < r) {
                    int mid = (l + r + 1) >> 1;
                    long long sub = hashing.query(i + 1, i + mid);
                    if (s[mid].count(sub)) {
                        l = mid;
                    } else {
                        r = mid - 1;
                    }
                }
                return l;
            };
    
            int ans = 0, last = 0, mx = 0;
            for (int i = 0; i < n; i++) {
                int dist = f(i);
                mx = max(mx, i + dist);
                if (i == last) {
                    if (i == mx) {
                        return -1;
                    }
                    last = mx;
                    ans++;
                }
            }
            return ans;
        }
    };
    
    
  • class Hashing:
        __slots__ = ["mod", "h", "p"]
    
        def __init__(self, s: List[str], base: int, mod: int):
            self.mod = mod
            self.h = [0] * (len(s) + 1)
            self.p = [1] * (len(s) + 1)
            for i in range(1, len(s) + 1):
                self.h[i] = (self.h[i - 1] * base + ord(s[i - 1])) % mod
                self.p[i] = (self.p[i - 1] * base) % mod
    
        def query(self, l: int, r: int) -> int:
            return (self.h[r] - self.h[l - 1] * self.p[r - l + 1]) % self.mod
    
    
    class Solution:
        def minValidStrings(self, words: List[str], target: str) -> int:
            def f(i: int) -> int:
                l, r = 0, min(n - i, m)
                while l < r:
                    mid = (l + r + 1) >> 1
                    sub = hashing.query(i + 1, i + mid)
                    if sub in s[mid]:
                        l = mid
                    else:
                        r = mid - 1
                return l
    
            base, mod = 13331, 998244353
            hashing = Hashing(target, base, mod)
            m = max(len(w) for w in words)
            s = [set() for _ in range(m + 1)]
            for w in words:
                h = 0
                for j, c in enumerate(w, 1):
                    h = (h * base + ord(c)) % mod
                    s[j].add(h)
            ans = last = mx = 0
            n = len(target)
            for i in range(n):
                dist = f(i)
                mx = max(mx, i + dist)
                if i == last:
                    if i == mx:
                        return -1
                    last = mx
                    ans += 1
            return ans
    
    
  • type Hashing struct {
    	p   []int64
    	h   []int64
    	mod int64
    }
    
    func NewHashing(word string, base int64, mod int64) *Hashing {
    	n := len(word)
    	p := make([]int64, n+1)
    	h := make([]int64, n+1)
    	p[0] = 1
    	for i := 1; i <= n; i++ {
    		p[i] = (p[i-1] * base) % mod
    		h[i] = (h[i-1]*base + int64(word[i-1])) % mod
    	}
    	return &Hashing{p, h, mod}
    }
    
    func (hashing *Hashing) Query(l, r int) int64 {
    	return (hashing.h[r] - hashing.h[l-1]*hashing.p[r-l+1]%hashing.mod + hashing.mod) % hashing.mod
    }
    
    func minValidStrings(words []string, target string) (ans int) {
    	base, mod := int64(13331), int64(998244353)
    	hashing := NewHashing(target, base, mod)
    
    	m, n := 0, len(target)
    	for _, w := range words {
    		m = max(m, len(w))
    	}
    
    	s := make([]map[int64]bool, m+1)
    
    	f := func(i int) int {
    		l, r := 0, int(math.Min(float64(n-i), float64(m)))
    		for l < r {
    			mid := (l + r + 1) >> 1
    			sub := hashing.Query(i+1, i+mid)
    			if s[mid][sub] {
    				l = mid
    			} else {
    				r = mid - 1
    			}
    		}
    		return l
    	}
    
    	for _, w := range words {
    		h := int64(0)
    		for j := 0; j < len(w); j++ {
    			h = (h*base + int64(w[j])) % mod
    			if s[j+1] == nil {
    				s[j+1] = make(map[int64]bool)
    			}
    			s[j+1][h] = true
    		}
    	}
    
    	var last, mx int
    
    	for i := 0; i < n; i++ {
    		dist := f(i)
    		mx = max(mx, i+dist)
    		if i == last {
    			if i == mx {
    				return -1
    			}
    			last = mx
    			ans++
    		}
    	}
    	return ans
    }
    
    

All Problems

All Solutions