京东技术岗笔试真题 - 01串划分(C++/Py/Java /Js/Go)
·
01串划分(C++/Py/Java /Js/Go)题解
京东技术岗 0314笔试 第二题
题目内容
小钟有一个长度为 nnn 的 010101 串 sss (仅由字符 000 和 111 组成,如 010110101011010101101 ),还有 mmm 个数字 a1,a2,...,ama_1,a_2,...,a_ma1,a2,...,am 。
他想知道:是否能选择 mmm 个不相交的区间 [l1,r1],[l2,r2],...,[lm,rm][l_1,r_1],[l_2,r_2],...,[l_m,r_m][l1,r1],[l2,r2],...,[lm,rm],使得每个数字 aia_iai 的二进制表示(无前置000 , 000 的二进制就是 "000 "),都能被 sss 中对应的连续子串 s[li..ri]s[l_i..r_i]s[li..ri] 精确表示。
输入描述
输入包括多组测试数据。
1.第一行包括一个正整数 T(1≤T≤20)T(1≤T≤20)T(1≤T≤20),表示测试数据组数。
2.每组测试数据:
- 第一行有两个整数 n(1≤n≤100),m(1≤m≤6)n(1≤n≤100),m(1≤m≤6)n(1≤n≤100),m(1≤m≤6),分别表示 010101 串 sss 的长度和数字个数。
- 第二行有一行长度为 nnn 的 010101 串 sss 。
- 第三行有 mmm 个整数 a1,a2,...am(0≤ai<210)a_1,a_2,...a_m(0≤a_i<2^{10})a1,a2,...am(0≤ai<210),表示待匹配的数字。
输出描述
对于每组测试数据,输出一行:
- 若存在满足条件的 mmm 个不相交区间,输出 YESYESYES
- 否则输出 NONONO
样例1
输入
2
5 2
10110
2 1
5 1
00000
1
输出
YES
NO
说明
对于第一组测试数据,222 的二进制表示为 101010,111 的二进制表示为 111 ,其中一种可以选择的区间 为 [1,2]、[3,3][1,2]、[3,3][1,2]、[3,3]。
对于第二组测试数据,111 的二进制表示为 111,由于 010101 串中不存在字符 111,故答案一定不存在。
思路
状态DP + KMP
- 将每组输入的数字转换为二进制字符串
- 使用
kmp算法预处理每个数字二进制在s中存在的所有位置。 - 由于m比较小,可以使用状态dp枚举进行求解,
dp[mask]表示的含义为选择mask二进制为1位置的数之后,右端点的最小值. - 初始设置dp[0] = -1,其它设置一个认为不可达值, 枚举mask为
[1, 2^m-1], 状态转移过程为- 假设
mask不可达直接跳过,无法进行状态转移 - 尝试选择当前
mask未选择的数i,考虑加入i,枚举i在s中所有位置区间[l,r]- 如果
dp[mask] < l肯定不会发生重叠,更新dp[maks | 1 << i] = min(dp[maks | 1 << i], y) - 大于等于说明会发生冲突
- 如果
- 假设
- 最后判断
2^m -1是否可达即可
C++
#include<bits/stdc++.h>
using namespace std;
string intToStr(int x) {
if (x == 0) {
return "0";
}
string s;
while (x > 0) {
s += (x % 2) ? "1" : "0";
x /= 2;
}
reverse(s.begin(), s.end());
return s;
}
bool solve(int n, int m, string s,vector<int>& a) {
// 将数组转换为二进制字符串
vector<string> nums(m);
for (int i = 0; i < m; i++) {
int val = a[i];
nums[i] = intToStr(val);
}
// 记录每个数再s中匹配的位置
vector<vector<pair<int,int>>> index(m);
int k = 0;
// 使用kmp加快匹配
for (string num : nums) {
int len = num.size();
vector<int> pi(len);
for (int i = 1, j = 0; i < len; i++) {
while (j && num[j] != num[i]) {
j = pi[j - 1];
}
if (num[i] == num[j]) {
j++;
}
pi[i] = j;
}
for (int i = 0, j = 0; i < s.size(); i++) {
while (j && s[i] != num[j]) {
j = pi[j-1];
}
if (s[i] == num[j]) {
j++;
}
if (j == len) {
int l = i - len + 1;
index[k].push_back({l, i});
j = pi[j-1];
}
}
k++;
}
vector<int> dp(1 << m, INT_MAX);
dp[0] = -1;
for (int mask = 0; mask < (1 << m); mask++) {
if (dp[mask] == INT_MAX) {
continue;
}
for (int i = 0; i < m; i++) {
// 已经被处理
if (mask & 1 << i) {
continue;
}
for (auto [x, y] : index[i]) {
if (dp[mask] < x) {
dp[mask | (1<<i)] = min(dp[mask | (1<<i)], y);
}
}
}
}
return dp[(1<<m)-1]!=INT_MAX;
}
int main() {
ios_base::sync_with_stdio(false);
cin.tie(nullptr);
int T;
cin >> T;
while (T--) {
int n, m;
cin >> n >> m;
string s;
cin >> s;
vector<int> a(m);
for (int i = 0; i < m; i++) {
cin >> a[i];
}
bool flag = solve(n, m, s, a);
if (flag) {
cout << "YES" << endl;
} else {
cout << "NO" << endl;
}
}
}
java
import java.io.*;
import java.util.*;
public class Main {
static String intToStr(int x) {
if (x == 0) {
return "0";
}
StringBuilder sb = new StringBuilder();
while (x > 0) {
sb.append((x % 2) == 1 ? '1' : '0');
x /= 2;
}
return sb.reverse().toString();
}
static boolean solve(int n, int m, String s, int[] a) {
// 将数组转换为二进制字符串
String[] nums = new String[m];
for (int i = 0; i < m; i++) {
nums[i] = intToStr(a[i]);
}
// 记录每个数在s中匹配的位置
List<List<int[]>> index = new ArrayList<>();
for (int i = 0; i < m; i++) {
index.add(new ArrayList<>());
}
int k = 0;
// 使用KMP加快匹配
for (String num : nums) {
int len = num.length();
int[] pi = new int[len];
for (int i = 1, j = 0; i < len; i++) {
while (j > 0 && num.charAt(j) != num.charAt(i)) {
j = pi[j - 1];
}
if (num.charAt(i) == num.charAt(j)) {
j++;
}
pi[i] = j;
}
for (int i = 0, j = 0; i < s.length(); i++) {
while (j > 0 && s.charAt(i) != num.charAt(j)) {
j = pi[j - 1];
}
if (s.charAt(i) == num.charAt(j)) {
j++;
}
if (j == len) {
int l = i - len + 1;
index.get(k).add(new int[]{l, i});
j = pi[j - 1];
}
}
k++;
}
int[] dp = new int[1 << m];
Arrays.fill(dp, Integer.MAX_VALUE);
dp[0] = -1;
for (int mask = 0; mask < (1 << m); mask++) {
if (dp[mask] == Integer.MAX_VALUE) {
continue;
}
for (int i = 0; i < m; i++) {
// 已经被处理
if ((mask & (1 << i)) != 0) {
continue;
}
for (int[] p : index.get(i)) {
int x = p[0];
int y = p[1];
if (dp[mask] < x) {
dp[mask | (1 << i)] = Math.min(dp[mask | (1 << i)], y);
}
}
}
}
return dp[(1 << m) - 1] != Integer.MAX_VALUE;
}
public static void main(String[] args) throws Exception {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
StringTokenizer st;
int T = Integer.parseInt(br.readLine());
while (T-- > 0) {
st = new StringTokenizer(br.readLine());
int n = Integer.parseInt(st.nextToken());
int m = Integer.parseInt(st.nextToken());
String s = br.readLine();
st = new StringTokenizer(br.readLine());
int[] a = new int[m];
for (int i = 0; i < m; i++) {
a[i] = Integer.parseInt(st.nextToken());
}
boolean flag = solve(n, m, s, a);
if (flag) {
System.out.println("YES");
} else {
System.out.println("NO");
}
}
}
}
python
import sys
def intToStr(x):
if x == 0:
return "0"
s = []
while x > 0:
s.append('1' if x % 2 else '0')
x //= 2
return ''.join(reversed(s))
def solve(n, m, s, a):
# 将数组转换为二进制字符串
nums = [intToStr(x) for x in a]
# 记录每个数在s中匹配的位置
index = [[] for _ in range(m)]
k = 0
# 使用KMP加快匹配
for num in nums:
length = len(num)
pi = [0] * length
j = 0
for i in range(1, length):
while j and num[j] != num[i]:
j = pi[j - 1]
if num[i] == num[j]:
j += 1
pi[i] = j
j = 0
for i in range(len(s)):
while j and s[i] != num[j]:
j = pi[j - 1]
if s[i] == num[j]:
j += 1
if j == length:
l = i - length + 1
index[k].append((l, i))
j = pi[j - 1]
k += 1
dp = [2 ** 31 - 1] * (1 << m)
dp[0] = -1
for mask in range(1 << m):
if dp[mask] == 2 ** 31 - 1:
continue
for i in range(m):
# 已经被处理
if mask & (1 << i):
continue
for x, y in index[i]:
if dp[mask] < x:
nxt = mask | (1 << i)
dp[nxt] = min(dp[nxt], y)
return dp[(1 << m) - 1] != 2 ** 31 - 1
def main():
input = sys.stdin.readline
T = int(input())
for _ in range(T):
n, m = map(int, input().split())
s = input().strip()
a = list(map(int, input().split()))
flag = solve(n, m, s, a)
if flag:
print("YES")
else:
print("NO")
if __name__ == "__main__":
main()
javascript
const readline = require("readline");
const rl = readline.createInterface({
input: process.stdin,
output: process.stdout
});
const input = [];
rl.on("line", (line) => {
input.push(line);
});
rl.on("close", () => {
let idx = 0;
function next() {
return input[idx++];
}
function intToStr(x) {
if (x === 0) {
return "0";
}
let s = [];
while (x > 0) {
s.push((x % 2) ? '1' : '0');
x = Math.floor(x / 2);
}
s.reverse();
return s.join('');
}
function solve(n, m, s, a) {
// 将数组转换为二进制字符串
const nums = new Array(m);
for (let i = 0; i < m; i++) {
nums[i] = intToStr(a[i]);
}
// 记录每个数在s中匹配的位置
const index = Array.from({ length: m }, () => []);
let k = 0;
// 使用KMP加快匹配
for (const num of nums) {
const len = num.length;
const pi = new Array(len).fill(0);
for (let i = 1, j = 0; i < len; i++) {
while (j && num[j] !== num[i]) {
j = pi[j - 1];
}
if (num[i] === num[j]) {
j++;
}
pi[i] = j;
}
for (let i = 0, j = 0; i < s.length; i++) {
while (j && s[i] !== num[j]) {
j = pi[j - 1];
}
if (s[i] === num[j]) {
j++;
}
if (j === len) {
const l = i - len + 1;
index[k].push([l, i]);
j = pi[j - 1];
}
}
k++;
}
const INF = 0x7fffffff;
const dp = new Array(1 << m).fill(INF);
dp[0] = -1;
for (let mask = 0; mask < (1 << m); mask++) {
if (dp[mask] === INF) {
continue;
}
for (let i = 0; i < m; i++) {
// 已经被处理
if (mask & (1 << i)) {
continue;
}
for (const [x, y] of index[i]) {
if (dp[mask] < x) {
const nxt = mask | (1 << i);
dp[nxt] = Math.min(dp[nxt], y);
}
}
}
}
return dp[(1 << m) - 1] !== INF;
}
const T = Number(next());
const ans = [];
for (let t = 0; t < T; t++) {
const [n, m] = next().split(' ').map(Number);
const s = next();
const a = next().split(' ').map(Number);
const flag = solve(n, m, s, a);
if (flag) {
ans.push("YES");
} else {
ans.push("NO");
}
}
console.log(ans.join('\n'));
});
Go
package main
import (
"bufio"
"fmt"
"os"
)
type Pair struct {
x int
y int
}
func intToStr(x int) string {
if x == 0 {
return "0"
}
bytes := make([]byte, 0)
for x > 0 {
if x%2 == 1 {
bytes = append(bytes, '1')
} else {
bytes = append(bytes, '0')
}
x /= 2
}
// 反转
for i, j := 0, len(bytes)-1; i < j; i, j = i+1, j-1 {
bytes[i], bytes[j] = bytes[j], bytes[i]
}
return string(bytes)
}
func solve(n int, m int, s string, a []int) bool {
// 将数组转换为二进制字符串
nums := make([]string, m)
for i := 0; i < m; i++ {
nums[i] = intToStr(a[i])
}
// 记录每个数在s中匹配的位置
index := make([][]Pair, m)
k := 0
// 使用KMP加快匹配
for _, num := range nums {
length := len(num)
pi := make([]int, length)
for i, j := 1, 0; i < length; i++ {
for j > 0 && num[j] != num[i] {
j = pi[j-1]
}
if num[i] == num[j] {
j++
}
pi[i] = j
}
for i, j := 0, 0; i < len(s); i++ {
for j > 0 && s[i] != num[j] {
j = pi[j-1]
}
if s[i] == num[j] {
j++
}
if j == length {
l := i - length + 1
index[k] = append(index[k], Pair{l, i})
j = pi[j-1]
}
}
k++
}
const INF = int(^uint(0) >> 1)
dp := make([]int, 1<<m)
for i := range dp {
dp[i] = INF
}
dp[0] = -1
for mask := 0; mask < (1 << m); mask++ {
if dp[mask] == INF {
continue
}
for i := 0; i < m; i++ {
// 已经被处理
if (mask & (1 << i)) != 0 {
continue
}
for _, p := range index[i] {
x := p.x
y := p.y
if dp[mask] < x {
nxt := mask | (1 << i)
if y < dp[nxt] {
dp[nxt] = y
}
}
}
}
}
return dp[(1<<m)-1] != INF
}
func main() {
in := bufio.NewReader(os.Stdin)
var T int
fmt.Fscan(in, &T)
for ; T > 0; T-- {
var n, m int
fmt.Fscan(in, &n, &m)
var s string
fmt.Fscan(in, &s)
a := make([]int, m)
for i := 0; i < m; i++ {
fmt.Fscan(in, &a[i])
}
flag := solve(n, m, s, a)
if flag {
fmt.Println("YES")
} else {
fmt.Println("NO")
}
}
}
更多推荐


所有评论(0)