break algorithm---双指针3:滑动窗口



声明:
算法基于https://labuladong.github.io/
python语言实现


滑动窗口:子串问题
sliding window template
76. Minimum Window Substring
3. Longest Substring Without Repeating Characters
438. Find All Anagrams in a String
567. Permutation in String




滑动窗口:子串问题



sliding window template


python

def slidingWindow(self, s: str, t: str) -> str:
    window = dict()
    need = dict()
    for c in t:
        need.setdefault(c, 0)
        need[c] += 1

    left = right = 0
    valid = 0  # valid表示窗口中满足need条件的字符个数,如果valid和len(need)的大小相同,则说明窗口已经满足条件,已经完全覆盖了串t。

    # answer relevant vars:record answer
    for right, in_win_char in enumerate(s):
        # 1.增大窗口
        # right:右移窗口指针,增大窗口
        # in_win_char:移入窗口的字符
        window.setdefault(in_win_char, 0)
        # 1.2 更新窗口内数据
        if in_win_char in need.keys():
            window[in_win_char] += 1
            if window[in_win_char] == need[in_win_char]:
                valid += 1


        # 2.debug position:
        # print("window: [%d, %d)\n" % (left,right));


        # 3.收缩窗口
        # 3.1 判断左侧窗口是否要收缩:找到可行解时,左侧窗口即可进行收缩。
        while (valid == len(need) | valid >= len(need)):
            # 3. 更新答案可能位置1

            # 3.3 缩小窗口
            # out_win_char:将移出窗口的字符
            out_win_char = s[left]
            # 缩小窗口
            left += 1
            # 3.4 更新窗口内数据
            if out_win_char in need.keys():
                if window[out_win_char] == need[out_win_char]:
                    valid -= 1
                window[out_win_char] -= 1

            # 3. 更新答案可能位置2


    return

双指针解决如下三类问题:
1.快慢指针:链表、归并排序找中点、链表成环判定
2.左右指针:数组问题、二分搜索、反转数组
3.滑动窗口:子串问题

Note:
python built-in function:
dict()

  1. len(dict)
  2. cmp(dict1,dict2)
    3.1 dict.get(key[, default=None])
    key=>存在:返回key对应的value
    不存在:返回default
    3.2 dict.setdefult(key[, default=None])
    类似dict.get(),
    但当key不存在时:不会返回default,而是添加该不存在的key,并将该值设为default。
    此时若设置了default值,返回default值;若为设置default值,默认为None,无返回值。
  3. dict.keys() # return: list[k1, k2, …]
    dict.values() # return: list[v1, v2, …]
    dict.items() # dict_items([(k1, v1), (k2, v2), …]) 以列表返回可遍历的(k,v)元组数组
    dict.has_key(key) # True/False
    dict.pop(key[, default]) # 删除key对应的value,
    # key存在:删value,并返回value值;
    # key不存在若设置了default:返回default值;
    # key不存在default未设置,报错:KeyError。
    dict.popitem() # (last_key, last_value) 删除并返回最后一对k-v

enumerate()
Python中的enumerate()是一个内置函数,用于为可迭代对象的每个项目分配索引。它在可迭代对象上添加一个循环,同时跟踪当前项并以可枚举的形式返回对象。这个对象可以在 for 循环中使用 list() 方法将其转换为列表。


Note:enumerate只能用于for循环,不能用于while循环。
Note:python中的for循环与while循环不等价,不可相互转换。区别于Java,c,c++等语言。


Python 仅使用两个循环:“While 循环”和“for 循环”。

  • While 循环 根据条件语句是真还是假 来执行。
  • for 循环称为迭代器,它 根据条件集迭代元素。
  • Python For 循环还可以用于一组其他各种事情(指定我们要循环的元素集合)
  • 断点在 For 循环中用于在任何特定点中断或终止程序
  • Continue 语句会继续打印出语句,并根据条件集打印出结果
  • “for循环”中的枚举函数返回我们正在查看的带有索引号的集合成员

  1. enumerate(sequence[, start=0])
    sequence: 可遍历对象:list、string、tuple、dict…
    组合为(start,value)索引序列 # start:对应index_0
    ***一般用于for循环,当索引start位不在for循环中使用时,可使用_单下划线作为占位符
  2. example:
    >>> list1=['a','b','c']
    >>> enumerate(list1)

    >>> list2=enumerate(list1)
    >>> list2

    >>> list2=list(enumerate(list1))
    >>> list2
    [(0, ‘a’), (1, ‘b’), (2, ‘c’)]
    >>> for i,element in enumerate(list1):print(i,element)
    0 a
    1 b
    2 c
    >>> for _,element in enumerate(list1):print(element)
    a
    b
    c
    >>>

java

/* 滑动窗口算法框架 */
void slidingWindow(string s, string t) {
    unordered_map<char, int> need, window;
    for (char c : t) need[c]++;
    
    int left = 0, right = 0;
    int valid = 0; 
    while (right < s.size()) {
        // c 是将移入窗口的字符
        char c = s[right];
        // 增大窗口
        right++;
        // 进行窗口内数据的一系列更新
        ...

        /*** debug 输出的位置 ***/
        printf("window: [%d, %d)\n", left, right);
        /********************/
        
        // 判断左侧窗口是否要收缩
        while (window needs shrink) {
            // d 是将移出窗口的字符
            char d = s[left];
            // 缩小窗口
            left++;
            // 进行窗口内数据的一系列更新
            ...
        }
    }
}


76. Minimum Window Substring

https://leetcode.com/problems/minimum-window-substring/

python:
solution1:使用window+need

class Solution:
    def minWindow(self, s: str, t: str) -> str:
        if len(s) < len(t):
            return ""

        # Note:不能初始化为window=need=dict(),否则二者指向同一对象,即:不同变量分开初始化!
        window = dict()
        need = dict()
        for c in t:
            need.setdefault(c, 0)
            need[c] += 1
        # print(need)

        left = 0
        right = 0
        valid = 0

        min_len = len(s) + 1
        min_str = ""
        # expand window:
        # Note:enumerate只能用于for循环,不能用于while循环
        for right, in_win_char in enumerate(s):
            # right:右窗口指针,右移扩大窗口
            # win_in_char:移入窗口中的字符

            # update window
            if in_win_char in need.keys():
                window.setdefault(in_win_char, 0)
                window[in_win_char] += 1
                if window[in_win_char] == need[in_win_char]:
                    valid += 1
                    # print("window[%c]:%d\n" % (in_win_char,window[in_win_char]))
                    # print("need[%c]:%d\n" % (in_win_char,need[in_win_char]))
                    # print("valid:%d\n" % valid)

            # debug position
            # print("window:[%d, %d)\n" % (left, right))

            # shrink window:找到可行解时,通过收缩窗口这一动作优化可行解,使其向最优解收缩
            while (valid == len(need)):
                # update answer
                if right - left < min_len:
                    min_len = right - left
                    min_str = s[left:right + 1]

                # out_win_char:移出窗口中的字符
                out_win_char = s[left]
                # left:左窗口指针,右移缩小窗口
                left += 1
                if out_win_char in need.keys():
                    if window[out_win_char] == need[out_win_char]:
                        valid -= 1
                    window[out_win_char] -= 1

        return min_str


def main():
    # solution1=Solution()
    # print(solution1.minWindow("ADOBECODEBANC", "ABC"))
    #
    # solution2=Solution()
    # print(solution2.minWindow("a", "a"))
    #
    # solution2=Solution()
    # print(solution2.minWindow("a", "aa"))

    # wrong answer
    # i:aa
    # o:a
    # e:aa
    # wrong reason:初始化为window=need=dict(),二者指向同一对象。
    solution2=Solution()
    print(solution2.minWindow("aa", "aa"))

if __name__ == '__main__':
    main()

solution2:仅使用need

class Solution:
    def minWindow(self, s: str, t: str) -> str:
        need = dict()
        for c in t:
            need.setdefault(c, 0)
            need[c] += 1
            
        left = 0
        right = 0
        
        valid = 0			# valid表示窗口中满足need条件的字符个数,如果valid和len(need)的大小相同,则说明窗口已经满足条件,已经完全覆盖了串t。
		#记录最小覆盖子串
        min_size = len(s)+1	# 最小覆盖子串长度初始化为字符串s长度加1
        min_str = ""
        for right, in_win_char in enumerate(s):
            # right:右移窗口指针,in_win_char:移入窗口的字符  
            
			#窗口内数据更新   
            if in_win_char in need:
                need[in_win_char] -= 1
                if need[in_win_char] == 0:
                valid += 1
                
            # 找到可行解
            while (valid == len(need)):
                # 记录可行解
                win_size = right - left
                #更新最小覆盖子串
                if win_size < min_size:
                    min_str = s[left:right+1]
                    min_size = win_size
                    
                # 移动左指针优化可行解,out_win_char是将移出窗口的字符
                out_win_char = s[left]
                if out_win_char in need:
                    need[out_win_char] += 1
                    if need[out_win_char] == 1:
                        valid -= 1
                left += 1
        return min_str

java:

string minWindow(string s, string t) {
    unordered_map<char, int> need, window;
    for (char c : t) need[c]++;

    int left = 0, right = 0;
    int valid = 0;
    // 记录最小覆盖子串的起始索引及长度
    int start = 0, len = INT_MAX;
    while (right < s.size()) {
        // c 是将移入窗口的字符
        char c = s[right];
        // 右移窗口
        right++;
        // 进行窗口内数据的一系列更新
        if (need.count(c)) {
            window[c]++;
            if (window[c] == need[c])
                valid++;
        }

        // 判断左侧窗口是否要收缩
        while (valid == need.size()) {
            // 在这里更新最小覆盖子串
            if (right - left < len) {
                start = left;
                len = right - left;
            }
            // d 是将移出窗口的字符
            char d = s[left];
            // 左移窗口
            left++;
            // 进行窗口内数据的一系列更新
            if (need.count(d)) {
                if (window[d] == need[d])
                    valid--;
                window[d]--;
            }                    
        }
    }
    // 返回最小覆盖子串
    return len == INT_MAX ?
        "" : s.substr(start, len);
}


3. Longest Substring Without Repeating Characters

https://leetcode.com/problems/longest-substring-without-repeating-characters/


python

class Solution:
    def lengthOfLongestSubstring(self, s: str) -> int:
        window = dict()

        left = 0
        right = 0

        res = 0
        # expand window
        for right, in_win_char in enumerate(s):
            # update window
            window.setdefault(in_win_char, 0)
            window[in_win_char] += 1

            # shrink window
            while window[in_win_char] > 1:
                # shrink window
                out_win_char = s[left]
                left += 1

                # update window
                window[out_win_char] -= 1

            # update answer
            res = max(res, right - left + 1)

        return res


def main():
    # Input: s = "abcabcbb"
    # Output: 3
    # Explanation: The answer is "abc", with the length of 3.
    solution1 = Solution()
    print(solution1.lengthOfLongestSubstring("abcabcbb"))

    # Input: s = "bbbbb"
    # Output: 1
    # Explanation: The answer is "b", with the length of 1.
    solution2 = Solution()
    print(solution2.lengthOfLongestSubstring("bbbbb"))


if __name__ == '__main__':
    main()



438. Find All Anagrams in a String

https://leetcode.com/problems/find-all-anagrams-in-a-string/


python

class Solution:
    def findAnagrams(self, s: str, p: str):
        window = dict()
        need = dict()
        for c in p:
            need.setdefault(c, 0)
            need[c] += 1

        left = 0
        right = 0
        valid = 0

        res = []
        # expand window
        for right, in_win_char in enumerate(s):
            # update window
            if in_win_char in need.keys():
                window.setdefault(in_win_char, 0)
                window[in_win_char] += 1
                if window[in_win_char] == need[in_win_char]:
                    valid += 1

            # shrink window
            while right - left + 1 >= len(p):
                # update answer
                if valid == len(need):
                    res.append(left)

                out_win_char = s[left]
                left += 1
                if out_win_char in need.keys():
                    if window[out_win_char] == need[out_win_char]:
                        valid -= 1
                    window[out_win_char] -= 1

        return res


def main():
    # Output: [0,1,2]
    solution1 = Solution()
    print(solution1.findAnagrams("abab", "ab"))

    # Output: [0,6]
    solution2 = Solution()
    print(solution2.findAnagrams("cbaebabacd", "abc"))

    # "baa"
    # "aa"
    # Output []
    # Expected [1]
    solution3 = Solution()
    print(solution3.findAnagrams("baa", "aa"))


if __name__ == '__main__':
    main()



567. Permutation in String

https://leetcode.com/problems/permutation-in-string/


python

class Solution:
    def checkInclusion(self, s1: str, s2: str) -> bool:
        window = dict()
        need = dict()
        for c in s1:
            need.setdefault(c, 0)
            need[c] += 1

        left = 0
        right = 0
        valid = 0

        # expand window
        for right, in_win_char in enumerate(s2):
            # update window
            if in_win_char in need.keys():
                window.setdefault(in_win_char, 0)
                window[in_win_char] += 1
                if window[in_win_char] == need[in_win_char]:
                    valid += 1

            # shrink window
            while right - left + 1 >= len(s1):
                # update answer
                if valid == len(need):
                    return True

                # shrink window
                out_win_char = s2[left]
                left += 1
                if out_win_char in need.keys():
                    if window[out_win_char] == need[out_win_char]:
                        valid -= 1
                    window[out_win_char] -= 1

        return False


def main():
    # Input: s1 = "ab", s2 = "eidbaooo"
    # Output: true
    # Explanation: s2 contains one permutation of s1("ba").
    solution1 = Solution()
    print(solution1.checkInclusion("ab", "eidbaooo"))

    # Input: s1 = "ab", s2 = "eidboaoo"
    # Output: false
    solution2 = Solution()
    print(solution2.checkInclusion(s1 = "ab", s2 = "eidboaoo"))

if __name__ == '__main__':
    main()

你可能感兴趣的:(algorithm,算法)