leetcode中几道与维护窗口相关的问题

leetcode中有几道题使用同一个思路,大致是先维护一个窗口,每次只移动窗口左侧或者右侧的边界,然后针对这个窗口内的元素进行处理。这种方式使用两个指针,可以将问题的运行时间降到O(n)内。

Longest Substring Without Repeating Characters:https://leetcode.com/problems/longest-substring-without-repeating-characters/

这道题我们维护一个窗口,每次将右边的窗口向前移动一位。另外维护一个hash表,标记当前窗口中的字符的位置,一旦右边的窗口遇到了当前窗口中的字符,说明有重复,将左边窗口移到当前窗口中重复字符的下一位,更新重复字符的位置为有窗口的位置。每次移动右窗口都更新当前的最大长度,知道有窗口移到最后一位。

这里hash table有一个对于字符串常用的用法,就是声明一个长度为256的数组,正好对应256个字符。

 1 class Solution {
 2 public:
 3     int lengthOfLongestSubstring(string s) {
 4         vector<int> visit(256, -1);
 5         int start = 0, end = 0, len = 0;
 6         while(end < s.length()) {
 7             if(visit[s[end]] >= start) {
 8                 start = visit[s[end]] + 1;
 9             }
10             visit[s[end]] = end;
11             len = max(end + 1 - start, len);
12             end++;
13         }
14         return len;
15     }
16 };

substring with concatenation of all words leetcode:https://leetcode.com/problems/substring-with-concatenation-of-all-words/

这道题的思路也是维护一个窗口和hash表。但是由于这道题的特殊性,需要维护两个hash,一个是不能改变的hash,用来存储字典;另一个是会变化的,都用来存储当前的窗口中访问的word以及每个word访问的次数。

为了是算法在O(n)时间内运行,这里还有一个技巧,(这个技巧也是使得这道题更难的原因),假设源字符串的长度为n,字典中单词的长度为wlen。因为不是一个字符,所以我们需要对源字符串所有长度为wlen的子串进行判断。做法是i从0到wlen-1个字符开始,得到初始考察的end为i, i+wlen, i+2*wlen, ...的长度为wlen的单词。这样就可以保证判断到所有的满足条件的串。因为每次扫描的时间复杂度是O(2*n/wlen)(每个单词不会被访问多于两次,一次是窗口右端,一次是窗口左端),总共扫描l次(i=0, ..., wlen-1),所以总复杂度是O(2*n/l*l)=O(n),是一个线性算法。

 1 class Solution {
 2 public:
 3     vector<int> findSubstring(string s, vector<string>& words) {
 4         unordered_map<string, int> stable_dict;
 5         for(int i = 0; i < words.size(); i++) {
 6             if(stable_dict.find(words[i]) == stable_dict.end())
 7                 stable_dict.insert(make_pair(words[i], 1));
 8             else
 9                 stable_dict[words[i]]++;
10         }
11         vector<int> res;
12         int wlen = words[0].size();
13         int i = 0;
14         while(i < wlen) {
15             int end = i;
16             int start = i;
17             int count = 0;
18             unordered_map<string, int> dict;
19             while(end < s.length()) {
20                 string cur = s.substr(end, wlen);
21                 string start_cur = s.substr(start, wlen);
22                 if(stable_dict.find(cur) != stable_dict.end()) {
23                     if(dict.find(cur) == dict.end())
24                         dict.insert(make_pair(cur, 0));
25                     if(dict[cur] < stable_dict[cur]) {
26                         dict[cur]++;
27                         count++;
28                         end += wlen;
29                     }
30                     else {
31                         if(count == words.size())
32                             res.push_back(start);
33                         dict[start_cur]--;
34                         count--;
35                         start += wlen;
36                     }
37                 }
38                 else {
39                     end += wlen;
40                     count = 0;
41                     start = end;
42                     dict.clear();
43                 }
44             }
45             i++;
46         }
47         return res;
48     }
49 };

Minimum Window Substring: https://leetcode.com/problems/minimum-window-substring/

这道题的思路和上一道很相似。区别是每次循环都要右移右指针,而移动左指针的条件是当所有的字典中的字符都在窗口中,停止移动的条件是有字符不在窗口中。这里要注意的一点是由于我们采取了纪录所有出现在窗口中的字典中字符的个数,所以如果某个字符的这个个数比字典中应有的个数多,也应当让左指针移动,并且减少这个值直到和字典的字符数一样多。

 1 class Solution {
 2 public:
 3     string minWindow(string s, string t) {
 4         string res = "";
 5         int start = 0, end = 0;
 6         int count = 0;
 7         vector<int> record(256, 0);
 8         vector<int> dict(256, 0);
 9         for(int i = 0; i < t.length(); i++) {
10             dict[t[i]]++;
11         }
12         while(end < s.length()) {
13             if(dict[s[end]] > 0) {
14                 record[s[end]]++;
15                 if(record[s[end]] <= dict[s[end]]) {
16                     count++;
17                 }
18                 if(count == t.length()) {
19                     while(dict[s[start]] == 0 || record[s[start]] > dict[s[start]]) {
20                         record[s[start]]--;
21                         start++;
22                     }
23                     res = res.length() == 0 ? s.substr(start, end + 1 - start) : res.length() < (end + 1 - start) ? res : s.substr(start, end + 1 - start);
24                     record[s[start]]--;
25                     count--;
26                     start++;
27                 }
28             }
29             end++;
30         }
31         return res;
32     }
33 };

可以看出这类窗口的问题其实是双指针扫描,关键点是判断两个指针的移动条件以及使用hash table保存窗口信息。

时间: 2024-10-25 16:39:03

leetcode中几道与维护窗口相关的问题的相关文章

Android4.2.2的Stagefright中编解码器数据流的维护

本文均属自己阅读源码的点滴总结,转账请注明出处谢谢. 欢迎和大家交流.qq:1037701636 email:[email protected] Android源码版本Version:4.2.2; 硬件平台 全志A31 前沿: 在前面的博文中,基本提到的是stagefright相关的控制流,具体分析了android架构中的MediaExtractor.AwesomePlayer.StagefrightPlayer.OMXCodec等的创建,底层OMXNodinstance实例的创建.分析了OMX

WebView中的视频全屏的相关操作

最近工作中,基本一直在用WebView,今天就把它整理下: WebView 顾名思义,就是放一个网页,一个看起来十分简单,但是用起来不是那么简单的控件. 首先你肯定要定义,初始化一个webview,其实网上的例子很多,我这里就简单的把一些WebView 中可能会用到的的很重要的属性以及支持全屏播放视频该怎么实现的代码粘出来,直接放到项目中去就行了 <span style="white-space:pre"></span><pre name="co

微软私有云分享(R2)27维护窗口的使用

维护窗口提供了计划外维护System Center 2012 R2的可能.在维护窗口所约定的时间内,可以独自对Hyper-V主机进行一些基础维护,如打补丁,关机更换硬件等操作.对于处于维护窗口的Hyper-V主机,SCVMM2012 R2不对其进行监视.同时相应的操作也不会在处于维护窗口中的Hyper-V主机进行.包括本章介绍的动态优化和电源优化,也需要在维护窗之外运行. 第1步,在"设置"对话框,点击"维护窗口"后,于顶部工具栏点击"创建维护窗口&quo

Leetcode中字符串总结

本文是个人对LeetCode中字符串类型题目的总结,纯属个人感悟,若有不妥的地方,欢迎指出. 一.有关数字 1.数转换 题Interger to roman和Roman to integer这两题是罗马数字和整数之间的相互转换,首先要懂得什么是罗马数字以及相应的组数规则.LeetCode的题中给出的数字最大的是3999,.针对第一题有两种解法:第一是列举出罗马数字在个十百千上的各种情况,形成一个二维矩阵,然后对整数不停的取余.除10来确定相应的罗马数字:第二种是先列出罗马数字组成情况,然后通过从

在Delphi的窗口单元中,如何调用其它窗口的单元。

在Delphi的窗口单元中,如何调用其它窗口的单元.(转载) . 在Delphi中简单的调用单元 unit实例 一,新建一个工程文件,默认的文件是unit1,代码如下:unit Unit1; interface uses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls; type TForm1 = class(TForm) Button1: TButton;

#14# SCCM管理 - 维护窗口

维护窗口 为读者提炼SCCM涉及的基础知识.注意事项.运行机制以及排错方法等信息是本系列文章的初衷,对于SCCM各组件及功能部署步骤方面的信息,网络中已有较多文章可以参考,因此本系列文章并不侧重于提供类似Step-by-Step的部署指南,还请见谅.同时由于个人能力和知识水平的限制,文中不免有纰漏和出错的地方,还望大家可以指正,非常感谢. 本篇文章主要讨论ConfigMgr中维护窗口(Maintenance Windows) 每个维护窗口定义了一个时间周期,用于限制SCCM客户端可执行强制部署的

leetcode中第一题twosum问题解答算法的可行性证明

leetcode中第一题twosum问题解答算法的可行性证明 一.引入 关于leetcode中第一题twosum问题,网上已有不少高人做出过解答,并提出了切实可行的算法实现.我在解答该题时参考了博客http://www.zixue7.com/article-9576-1.html的解答.为让读者更直观地阅读和理解本文,先简要摘录以上博客的内容如下: 题目还原 Two Sum Given an array of integers, find two numbers such that they a

delphi程序向另一个可执行程序发消息(使用GetForegroundWindow; 找出当前操作系统中活动的第一个窗口)

function FindWindowThroughWindowText(WindowText: string): THandle;var  hCurrentWindow: THandle;  cnt: Integer;  WindowTitle: array [0 .. 254] of Char;begin  Result := INVALID_HANDLE_VALUE; // 返回值预设为无效的句柄  hCurrentWindow := GetForegroundWindow; // 找出当

动态规划以及在leetcode中的应用

之前只是知道动态规划是通过组合子问题来解决原问题的,但是如何分析,如何应用一直都是一头雾水.最近在leetcode中发现有好几道题都可以用动态规划方法进行解决,就此做下笔录. 动态规划:应用于子问题重叠情况,原问题的多个子问题间可能含有相同的子子问题,当然,关于将原问题分解成子问题的思路,分治算法也是可行的,但是如果采用分治递归来解决就会出现一些问题.在重复的子问题的计算中,分治算法会忽略到重复问题,也就是说相同的问题,分治算法会计算多次,这样效率会很低.而动态规划算法会仔细安排求解顺序,对每个