给定长度为N的整数数组,以及M个互不相同的整数,请找出包含这M个整数的最短子数组。
例如:给定数组[4 2 1 3],包含数字集{2, 3}的最短子数组是[2 1 3],包含数字集{1, 3}的最短子数组是[1 3]。
第一行一个正整数T(T<=10),表示T个测试样例;
对于每个测试样例,
输入正整数N(N<=100,000),表示数组长度;
接下来输入N个正整数,所有整数都>=0且<=1,000,000,000;
输入正整数M(M<=N),表示M个互不相同的整数;
接下来输入M个整数,表示要查询的整数,已保证互不相同。
有部分测试样例满足N<=1,000。
输出T行,每行一个正整数,表示最短子数组的长度。如果不存在,输出0
1 4 4 2 1 3 2 2 3
3
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.IOException;
import java.util.HashMap;
public class Main {
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
int T = Integer.parseInt(br.readLine());
while(T-- > 0){
int n = Integer.parseInt(br.readLine());
String[] strArr = br.readLine().split(" ");
int[] arr = new int[n];
for(int i = 0; i < n; i++) arr[i] = Integer.parseInt(strArr[i]);
int m = Integer.parseInt(br.readLine());
strArr = br.readLine().split(" ");
HashMap<Integer, Integer> debt = new HashMap<>();
for(int i = 0; i < m; i++) debt.put(Integer.parseInt(strArr[i]), 1);
System.out.println(solve(arr, debt));
}
}
private static int solve(int[] arr, HashMap<Integer, Integer> debt) {
int all = debt.size(); // 总负债,刚开始每个数字欠一个
int left = 0, right = 0;
int minLen = arr.length + 1;
while(right < arr.length){
if(debt.containsKey(arr[right])){ // 只考虑目标数,不是目标数直接右移右指针
debt.put(arr[right], debt.get(arr[right]) - 1);
if(debt.get(arr[right]) == 0) all --; // arr[right]已经不欠了,总负债-1
while(all == 0) {
// 总负债为0,更新一下长度,同时收缩左边界
minLen = Math.min(minLen, right - left + 1);
if(debt.containsKey(arr[left])){
// 如果左端点的数是目标数,就要增加负债
debt.put(arr[left], debt.get(arr[left]) + 1);
if(debt.get(arr[left]) == 1) all++; // 重复丢失arr[left]不会增加总负债
}
left ++;
}
}
right ++;
}
// 长度一直没变过说明没有包含目标数的子数组
return minLen == arr.length + 1? 0: minLen;
}
} #include <iostream>
#include <vector>
#include <unordered_map>
using namespace std;
const int max_size=100000;
int min_array(vector<int>& nums,unordered_map<int,int>& sets,int m)
{
int min_length = max_size+1;
int i=0, j=0;//初始窗口
int count = 0;//窗口中已经包含的数字集中元素的个数
while(j<nums.size())//窗口右边往右扩张
{
if (sets.find(nums[j])!=sets.end())//如果该数在数字集中
{
if(sets[nums[j]]==0)//且该数出现次数为0
count++;//则包含元素个数++
sets[nums[j]]++;//该元素出现次数++
while (count==m)//当包含元素个数=数字集个数时,
{//说明已经包含了数字集所有元素,开始移动i,缩小窗口
if (sets.find(nums[i])!=sets.end())//当遇到数字集中的元素时
{
if (j - i + 1 < min_length)//更新最小长度
min_length = j - i + 1;
if (sets[nums[i]] > 0)//该元素出现次数--
sets[nums[i]]--;
if(sets[nums[i]]==0)//若某元素出现次数=0;表面已经到达有效窗口的极限位置
{
count--;//包含元素个数--,表明还差了一个元素。下次再遇到该元素时,又是有效窗口
i++;
break;
}
}
i++;
}
}
j++;
}
if (min_length == max_size + 1)
return 0;
else
return min_length;
}
int main()
{
int T;
cin >> T;
int n,m;
int num;
for (int i = 0; i < T; i++)
{
vector<int> nums;
unordered_map<int, int> sets;//数字集
cin >> n;
for (int j = 0; j < n; j++)
{
cin >> num;
nums.push_back(num);
}
cin >> m;
for (int j = 0; j < m; j++)
{
cin >> num;
sets[num] = 0;//初始化数字集中每个数字的出现次数
}
cout << min_array(nums,sets,m) << endl;
}
return 0;
} 给个python滑动窗口的代码
from collections import defaultdict
class Solution():
def f(self,n,m,src_arr,tgt_arr):
needed=defaultdict(int)
window=defaultdict(int)
for item in tgt_arr:
needed[item]+=1
needed_len=len(needed)
cur_len=0
min_len=100000
left,right=0,0
while right<n:
if src_arr[right] in needed:
pre=window[src_arr[right]]
window[src_arr[right]]+=1
if pre<needed[src_arr[right]] and window[src_arr[right]]>=needed[src_arr[right]]:
cur_len+=1 # 已经满足一个了
while cur_len==needed_len:# 所有的key满足了
min_len=min(min_len,right-left+1)
left_item=src_arr[left]
if left_item in needed:
window[src_arr[left]]-=1
if window[src_arr[left]]<needed[src_arr[left]]:
cur_len-=1
left+=1
right+=1 # 向右移动一格
return min_len if min_len!=100000 else 0
sol=Solution()
n=int(input().strip())
for i in range(n):
n=int(input().strip())
src=[int(item) for item in input().strip().split()]
m=int(input().strip())
tgt=[int(item) for item in input().strip().split()]
# print(n,src,m,tgt)
res=sol.f(n,m,src,tgt)
print(res)
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <string>
#include <vector>
#include <stack>
#include <queue>
#include <set>
#include <cctype>
#include <ctime>
#include <map>
using namespace std;
const int maxn=1e5+5;
int a[maxn],b[maxn],c[maxn],d[maxn];
bool vis[maxn];
int en,m,n;
int getid(int x){
return lower_bound(b+1,b+en+1,x)-b;
}
bool check(int len){
int cnt=0;
for(int i=1;i<=en;i++) d[i]=0;
for(int i=1;i<=len;i++){
if(c[a[i]]==1){
if(d[a[i]]==0) cnt++;
d[a[i]]++;
}
}
if(cnt==m) return true;
for(int i=len+1;i<=n;i++){
int p=i-len;
if(c[a[p]]){
if(d[a[p]]==1) cnt--;
d[a[p]]--;
}
if(c[a[i]]==1){
if(d[a[i]]==0) cnt++;
d[a[i]]++;
}
if(cnt==m) return true;
}
return false;
}
int main(){
int T;
ios::sync_with_stdio(false);
cin>>T;
while(T--){
cin>>n;
for(int i=1;i<=n;i++) cin>>a[i],b[i]=a[i],c[i]=0;
sort(b+1,b+n+1);
en=unique(b+1,b+n+1)-b-1;
for(int i=1;i<=n;i++) a[i]=getid(a[i]);
cin>>m;
bool flag=true;
for(int i=1;i<=m;i++) {
int k;
cin>>k;
int x=getid(k);
if(b[x]!=k) flag=false;
else c[x]=1;
}
if(flag){
int l=m,r=n;
while(l<=r){
int mid=(l+r)/2;
if(check(mid)) r=mid-1;
else l=mid+1;
}
printf("%d\n",l);
}else{
puts("0");
}
}
return 0;
}
import java.util.Scanner;
import java.util.*;
// 注意类名必须为 Main, 不要有任何 package xxx 信息
public class Main {
public static void main(String[] args) {
Scanner in = new Scanner(System.in);
// 注意 hasNext 和 hasNextLine 的区别
while (in.hasNextInt()) { // 注意 while 处理多个 case
int count=in.nextInt();
for(int i=0;i<count;i++){
int src=in.nextInt();
int[] nums=new int[src];
for(int j=0;j<src;j++){
nums[j]=in.nextInt();
}
int target=in.nextInt();
Map<Integer,List<Integer>> record=new HashMap<>();
Set<Integer> set=new HashSet<>();
PriorityQueue<int[]> queue=new PriorityQueue<>((a,b)->a[1]-b[1]);//数组位置升序
for(int j=0;j<target;j++){
record.put(in.nextInt(),new ArrayList<Integer>());
}
int right=0;
//记录目标值的坐标,从小到大
for(int j=0;j<src;j++){
if(record.containsKey(nums[j])){
record.get(nums[j]).add(j);
int position=record.get(nums[j]).size()-1;
if(set.add(nums[j])){
right=Math.max(right,j);
queue.add(new int[]{nums[j],j,position});
}
}
}
if(queue.size()!=target){
System.out.println(0);
}else{
int ans=right-queue.peek()[1]+1;//记录最小子数组长度
while(true){
int[] cur=queue.peek();
List<Integer> curList=record.get(cur[0]);
if(cur[2]<curList.size()-1){
//说明还存在变化的可能性
int future=curList.get(cur[2]+1);
if(future>right){
right=future;
}
queue.poll();
queue.add(new int[]{cur[0],future,cur[2]+1});
ans=Math.min(ans,right-queue.peek()[1]+1);
}else{
break;
}
}
System.out.println(ans);
}
}
}
}
}
#维护滑动窗,超时,只能60%
from collections import defaultdict
class Solution:
#判断窗内是否包含所有要求的数字
def window_contain_target(self, w1, w2):
res = True
for k,v in w2.items():
if k not in w1.keys()&nbs***bsp;w1[k] < v:
res = False
break
return res
#维护滑动窗
def minWindow(self, s: str, t: str) -> str:
left = 0
target = defaultdict(int)
window = defaultdict(int)
window_len = float("inf")
res = ""
for char in t:
target[char] += 1
#右扩滑动窗
for right in range(0, len(s)):
window[s[right]] += 1
#左缩滑动窗
while self.window_contain_target(window, target):
if window_len > (right-left+1):
window_len = right-left+1
res = s[left:right+1]
window[s[left]] -= 1
if window[s[left]] == 0:
del window[s[left]]
left += 1
return res
T = int(input())
for i in range(T):
n = int(input())
nums = [int(i) for i in input().split()]
m = int(input())
query = [int(i) for i in input().split()]
solution = Solution()
res = solution.minWindow(nums, query)
print(len(res)) #include<bits/stdc++.h>
using namespace std;
int main(){
int T; cin >> T;
while(T--) {
int N; cin >> N;
int a[N]; for(int i=0; i<N; ++i) cin >> a[i];
set<int> s;
int M; cin >> M;
for(int i=0, val; i<M; ++i) cin >> val, s.insert(val);
priority_queue<int, vector<int>, greater<int>> pq;
map<int, int> m;
int res = INT_MAX;
for(int i=0, cnt = 0; i<N; ++i) {
if(s.count( a[i] )) {
pq.push(i);
m[a[i]]++;
cnt += m[a[i]]==1;
}
if(cnt >= M) {
while(m[a[pq.top()]] > 1) m[a[pq.top()]]--, pq.pop();
res = min(res, i - pq.top() + 1);
}
}
cout << (res == INT_MAX ? 0 : res) << endl;
}
return 0;
} import sys
def min_len(nums, subnums, lengths):
sub_dict = {}
for i in range(len(subnums)):
sub_dict[subnums[i]] = -1
min_length = len(nums) + 1
find_num = 0
pos = 0
while pos < len(nums):
if sub_dict.get(nums[pos], -2) != -2:
if sub_dict[nums[pos]] == -1:
find_num += 1
sub_dict[nums[pos]] = pos
if find_num == len(subnums):
max_pos = max(sub_dict.values())
min_pos = min(sub_dict.values())
length = max_pos - min_pos + 1
if length < min_length:
min_length = length
sub_dict[nums[min_pos]] = -1
find_num -= 1
pos += 1
min_length = min_length if min_length != len(nums) + 1 else 0
lengths.append(min_length)
total = int(input())
lengths = []
for i in range(total):
sys.stdin.readline()
nums = sys.stdin.readline().strip().split()
nums = list(map(int, nums))
sys.stdin.readline()
subnums = sys.stdin.readline().strip().split()
subnums = list(map(int, subnums))
min_len(nums, subnums, lengths)
for length in lengths:
print(length) ## 60%,超时了
def solve(nums, child_nums):
num_dict = {}
window = {}
length = float("inf")
left, right = 0, 0
for num in child_nums:
num_dict[num] = num_dict.get(num, 0) + 1
target = len(num_dict.keys())
while right < len(nums):
if nums[right] in child_nums:
window[nums[right]] = window.get(nums[right], 0) + 1
if window[nums[right]] == num_dict[nums[right]]:
target -= 1
while target == 0:
length = min(length, right - left + 1)
if nums[left] in child_nums:
window[nums[left]] -= 1
if window[nums[left]] < num_dict[nums[right]]:
target += 1
left += 1
right += 1
return length if length != float("inf") else 0
N = int(input())
for _ in range(N):
## get data
lens = int(input())
nums = list(map(int, input().strip().split()))
short_lens = int(input())
child_nums = list(map(int, input().strip().split()))
print(solve(nums, child_nums)) start和end两个变量记录位置,然后通过字典记录需要的字符串的个数,key为需要的字符,val为个数,额外使用一个计数变量satisfied记录满足匹配条件的字符个数,当其值等于要查找的子串长度时说明找到了满足条件的子串。end并检查是否是需要的字符并计数,当数量满足时开始移动左边界start从而缩小范围,直到end遍历到数组的最后。 def find_min_length(M,N,m_nums,need_dict):
min_length = 100000
satisfied = 0
#存储目标字符串中需要的字符的个数
src_dict = {}
start,end = 0,0
#滑动窗口最后的位置,end到达数组尾
while end < M:
# end向右滑动知道找到包含need所有字符的窗口
if m_nums[end] in need_dict.keys():
src_dict[m_nums[end]] = src_dict.get(m_nums[end],0)+1
if src_dict[m_nums[end]] == need_dict[m_nums[end]]:
satisfied += 1
# 找到满足条件的子串后求其长度,并移动左边的窗口坐标
while satisfied == N:
min_length = min(min_length,end-start+1)
if m_nums[start] in need_dict.keys():
src_dict[m_nums[start]] -= 1
# 重新判断新的窗口是否符合条件,不符合条件的话需要移动右窗口
if src_dict[m_nums[start]] < need_dict[m_nums[start]]:
satisfied -= 1
start += 1
end += 1
return min_length if min_length != 100000 else 0
def main():
T = int(input())
for i in range(T):
M = int(input())
m_nums = list(map(int,input().split()))
N = int(input())
n_nums = list(map(int,input().split()))
need_dict = {}
for i in range(N):
need_dict[n_nums[i]] = need_dict.get(n_nums[i],0)+1
min_length = find_min_length(M,N,m_nums, need_dict)
print(min_length)
main()
def subArraySerach(): T = int(input()) ret_res = [] for i in range(T): ret_res.append(0) for tt in range(T): N = int(input()) array_o = list(map(int, input().split())) M = int(input()) array_s = list(map(int, input().split())) length = [] if M > N&nbs***bsp;N == 0&nbs***bsp;M == 0: print(0) break for i in range(N - M + 1): length.append(0) for i in range(N - M + 1): j = 0 head_flag = -1 tail_flag = -1 length_flag = i while i < N and j < M: if array_o[i] == array_s[j]: if j == 0: head_flag = i if j == M - 1: tail_flag = i i = i + 1 j = j + 1 else: i = i + 1 if head_flag != -1 and tail_flag != -1: length[length_flag] = tail_flag - head_flag + 1 tmp = sorted(list(set(length))) if 0 in length: ret_res[tt] = tmp[1] else: ret_res[tt] = tmp[0] for ret in ret_res: print(ret) if __name__ == "__main__": subArraySerach() pass
#include <iostream>
#include <vector>
#include <unordered_map>
using namespace std;
int func(vector<int>& v, vector<int>& u)
{
unordered_map<int, int> need, window;
for(int i: u)
need[i]++;
int l = 0, r = 0;
int valid = 0;
int ans = v.size() + 1;
while(r < v.size())
{
int t = v[r];
r++;
if(need.count(t))
{
if(need.count(t))
{
window[t]++;
if(need[t] == window[t])
valid++;
}
}
while(valid == need.size())
{
ans = std::min(ans, r - l);
int t = v[l];
l++;
if(need.count(t))
{
if(need[t] == window[t])
valid--;
window[t]--;
}
}
}
return ans == v.size() + 1? 0: ans;
}
int main()
{
int T;
cin>>T;
while(T--)
{
int M, N, t;
cin>>N;
vector<int> v;
while(N--)
{
cin>>t;
v.push_back(t);
}
cin>>M;
vector<int> u;
while(M--)
{
cin>>t;
u.push_back(t);
}
cout<<func(v, u)<<endl;
}
}