题解 | 可匹配子段计数

可匹配子段计数

https://www.nowcoder.com/practice/cfc8ae6269cd445d83686f12da66023c

解决方案:滑动窗口 + 哈希计数优化

这是一个经典的定长滑动窗口问题。

  1. 预处理数组 b:使用哈希表(或数组,如果数值范围可控)记录数组 b 中每个数字出现的频率。
  2. 维护窗口计数:在数组 a 上维护一个长度为 m 的窗口。记录窗口内每个数字出现的频率。
  3. 维护匹配贡献度 (currentMatch)
  4. 当我们向窗口增加一个元素 x 时:如果窗口内 x 的数量仍然小于或等于 b 中 x 的数量,说明这个新加入的 x 贡献了一个有效匹配。当我们从窗口移除一个元素 y 时:如果窗口内 y 的数量原本小于或等于 b 中 y 的数量,说明移除它会损失一个有效匹配。
  5. 计数:每移动一次窗口,检查 currentMatch 是否 <= k。
import java.util.*;
import java.io.*;

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().trim());

        while (t-- > 0) {
            String[] nmk = br.readLine().split(" ");
            int n = Integer.parseInt(nmk[0]);
            int m = Integer.parseInt(nmk[1]);
            int k = Integer.parseInt(nmk[2]);

            int[] a = new int[n];
            String[] lineA = br.readLine().split(" ");
            for (int i = 0; i < n; i++) a[i] = Integer.parseInt(lineA[i]);

            int[] b = new int[m];
            String[] lineB = br.readLine().split(" ");
            Map<Integer, Integer> bCount = new HashMap<>();
            for (int i = 0; i < m; i++) {
                b[i] = Integer.parseInt(lineB[i]);
                bCount.put(b[i], bCount.getOrDefault(b[i], 0) + 1);
            }

            // 开始滑动窗口
            Map<Integer, Integer> windowCount = new HashMap<>();
            int currentMatch = 0;
            int validSubsegments = 0;

            // 初始化第一个长度为 m 的窗口
            for (int i = 0; i < m; i++) {
                int val = a[i];
                int countInWindow = windowCount.getOrDefault(val, 0);
                int countInB = bCount.getOrDefault(val, 0);

                if (countInWindow < countInB) {
                    currentMatch++;
                }
                windowCount.put(val, countInWindow + 1);
            }

            if (currentMatch >= k) validSubsegments++;

            // 滑动窗口向右移动
            for (int i = m; i < n; i++) {
                // 移除左侧元素
                int leftVal = a[i - m];
                int leftCount = windowCount.get(leftVal);
                if (leftCount <= bCount.getOrDefault(leftVal, 0)) {
                    currentMatch--;
                }
                windowCount.put(leftVal, leftCount - 1);

                // 加入右侧元素
                int rightVal = a[i];
                int rightCount = windowCount.getOrDefault(rightVal, 0);
                if (rightCount < bCount.getOrDefault(rightVal, 0)) {
                    currentMatch++;
                }
                windowCount.put(rightVal, rightCount + 1);

                if (currentMatch >= k) validSubsegments++;
            }

            System.out.println(validSubsegments);
        }
    }
}

全部评论

相关推荐

1.自我介绍2.介绍一下mcp,&nbsp;skills3.了解react哪些状态管理库4.对话是sse还是什么?是用fetch还是EventSource?5.ts中的any&nbsp;和&nbsp;unknown讲一讲6.是直接用组件库的组件还是自己封装了一些别的7.代码输出题1function&nbsp;main()&nbsp;{{var&nbsp;a&nbsp;=&nbsp;1let&nbsp;b&nbsp;=&nbsp;2}console.log(a);console.log(b);}main()console.log(a);8.什么是块级作用域&nbsp;全局作用域&nbsp;函数作用域9.代码输出题2for&nbsp;(var&nbsp;i&nbsp;=&nbsp;0;i&nbsp;&amp;lt;&nbsp;5;i++)&nbsp;{setTimeout(()&nbsp;=&amp;gt;&nbsp;{console.log(i);},&nbsp;100);}10.代码输出题3for&nbsp;(var&nbsp;i&nbsp;=&nbsp;0;&nbsp;i&nbsp;&amp;lt;&nbsp;5;&nbsp;i++){function&nbsp;printText(temp)&nbsp;{setTimeout(()&nbsp;=&amp;gt;&nbsp;{console.log(temp);},&nbsp;100);}printText(i)}11.代码输出题4for(var&nbsp;i&nbsp;=&nbsp;0;i&nbsp;&amp;lt;&nbsp;5;i++){function&nbsp;printText(temp)&nbsp;{var&nbsp;temp&nbsp;=&nbsp;isetTimeout(()&nbsp;=&amp;gt;&nbsp;{console.log(temp);},&nbsp;100);}printText(i)}12.代码输出题5for(var&nbsp;i&nbsp;=&nbsp;0;i&nbsp;&amp;lt;&nbsp;5;i++){function&nbsp;printText(temp)&nbsp;{setTimeout(()&nbsp;=&amp;gt;&nbsp;{var&nbsp;temp&nbsp;=&nbsp;iconsole.log(temp);},&nbsp;100);}printText(i)}13.点击控制台输出题export&nbsp;default&nbsp;function&nbsp;App()&nbsp;{const&nbsp;[count,&nbsp;setCount]&nbsp;=&nbsp;useState(0)console.log('render',count)return&nbsp;(&lt;div&gt;&lt;h1&gt;{count}&lt;/h1&gt;{setCount(count&nbsp;+&nbsp;1)setTimeout(()&nbsp;=&amp;gt;&nbsp;console.log('setTimeout',&nbsp;count),&nbsp;1000)}}&amp;gt;+1&lt;/div&gt;)}//这个组件点击按钮后,控制台的输出顺序和值如下://&nbsp;1.&nbsp;render&nbsp;1&nbsp;(组件重新渲染,&nbsp;count&nbsp;更新为&nbsp;1)//&nbsp;2.&nbsp;setTimeout&nbsp;0&nbsp;(1秒后输出,注意这里是&nbsp;0&nbsp;而不是&nbsp;1)14.算法:给有序数组arr&nbsp;=&nbsp;[-4,&nbsp;-1,&nbsp;0,&nbsp;3,&nbsp;5],返回平方后的排序//&nbsp;有序数组平方后排序const&nbsp;arr&nbsp;=&nbsp;[-4,&nbsp;-1,&nbsp;0,&nbsp;3,&nbsp;5]function&nbsp;solution(arr)&nbsp;{const&nbsp;len&nbsp;=&nbsp;arr.lengthconst&nbsp;result&nbsp;=&nbsp;new&nbsp;Array(len)let&nbsp;left&nbsp;=&nbsp;0let&nbsp;right&nbsp;=&nbsp;len&nbsp;-&nbsp;1let&nbsp;index&nbsp;=&nbsp;len&nbsp;-&nbsp;1while&nbsp;(left&nbsp;&amp;lt;=&nbsp;right)&nbsp;{if&nbsp;(arr[left]&nbsp;*&nbsp;arr[left]&nbsp;&amp;gt;&nbsp;arr[right]&nbsp;*&nbsp;arr[right])&nbsp;{result[index]&nbsp;=&nbsp;arr[left]&nbsp;*&nbsp;arr[left]left++}&nbsp;else&nbsp;{result[index]&nbsp;=&nbsp;arr[right]&nbsp;*&nbsp;arr[right]right--}index--}return&nbsp;result}console.log(solution(arr));15.反问
查看14道真题和解析
点赞 评论 收藏
分享
评论
点赞
收藏
分享

创作者周榜

更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务