算法入门(LeetCode)——滑动窗口

3. 无重复字符的最长子串

1. 题目

给定一个字符串 s ,请你找出其中不含有重复字符的 最长子串 的长度。

输入: s = "abcabcbb"
输出: 3 
解释: 因为无重复字符的最长子串是 "abc",所以其长度为 3

无重复字符的最长子串

2. 代码

c++

#include <stdio.h>
#include <unordered_set>
#include <math.h>
#include <iostream>

class Solution {
public:
    int lengthOfLongestSubstring(string s) {
        int length = s.length();
		if (length == 0) { return 0; }
		
		int left = 0;
		int maxStr = 0;
		// 方法一
//		std::unordered_set<char> set;
//		for (int i = 0; i <length; i++) {
//			while (set.find(s[i]) != set.end()){ //找得到
//				set.erase(s[left]);
//				left++;
//			}
//			set.insert(s[i]);
//			maxStr = std::max(maxStr, i-left+1);
//		}
		// 方法二
		std::unordered_map<char,int> map;
		for (int i = 0; i <length; i++) {
			if (map.find(s[i]) != map.end()) {
				left = std::max(left, map[s[i]] + 1);
			}
			map[s[i]] = i;
			maxStr = std::max(maxStr, i-left+1);
		}
		return maxStr;
    }
};

java

	public int lengthOfLongestSubstring(String s) {
        if (s.length()==0) return 0;
        Map<Character, Integer> map = new HashMap<Character, Integer>();
        int max = 0;
        int left = 0;
        for(int i = 0; i < s.length(); i ++){
            if(map.containsKey(s.charAt(i))){
                left = Math.max(left,map.get(s.charAt(i)) + 1);
            }
            map.put(s.charAt(i),i);
            max = Math.max(max,i-left+1);
        }
        return max;
        
    }
3. 题解

  滑动窗口算法在一个特定大小的字符串或数组上进行操作,而不在整个字符串和数组上操作,这样就降低了问题的复杂度,从而也达到降低了循环的嵌套深度
  遍历string中字符,找出不重复的子字符串存入集合,不重复子字符串的满足条件是最后一个字符+1 与之前集合中字符重复,此时从集合中删除重复字符以及该字符前面的字符,窗口滑动到重复字符后面一个字符

567. 字符串的排列

1. 题目

给你两个字符串 s1 和 s2 ,写一个函数来判断 s2 是否包含 s1 的排列。如果是,返回 true ;否则,返回 false

输入:s1 = "ab" s2 = "eidbaooo"
输出:true
解释:s2 包含 s1 的排列之一 ("ba").
2. 代码

自己想到的解法,提交超时了

	bool checkInclusion(std::string s1, std::string s2) {
		int n1 = s1.length();
		int n2 = s2.length();
		if (n1 >  n2) {
			return false;
		}
		// 将s1中每个字符串中的字符以及字符个数存入map
		std::map<char, int> map1;
		for (int i = 0; i < n1; i++) {
			map1[s1[i]]++;
		}
		std::map<char, int> map2;
		int left = 0;
		while ((left + n1 - 1) < n2) {
			int flag = 1;
			map2.clear();
			// 将s2中长度为n1的子字符串中每个字符串中的字符以及字符个数存入map
			for (int i = left; i < left+n1; i++) {
				map2[s2[i]]++;
			}
			// 比较两个map是否相等
			for (auto it: map2) {
				auto iter = map1.find(it.first);
				if (iter == map1.end()) {
					flag = 0;
					break;
				}
				if (it.second != iter->second){
					flag = 0;
					break;
				}
			}
			// 相等返回true
			if (flag) { return true;}
			// 不相等,继续比较下一个窗口
			left ++;
		}
		return false;
    }

官方示例:

class Solution {
public:
    bool checkInclusion(string s1, string s2) {
        int n = s1.length(), m = s2.length();
        if (n > m) {
            return false;
        }
        vector<int> cnt1(26), cnt2(26);
        for (int i = 0; i < n; ++i) {
        	// 将字符串当前位置的字符转化为cnt的下标,一一对应起来,0<=s[i]-'a'<=26,cnt初始化的时候就是长度就是26
            ++cnt1[s1[i] - 'a'];
            ++cnt2[s2[i] - 'a'];
        }
//		for (int a : cnt1) {std::cout << a ;}
//		std::cout <<std::endl;
//		for (int b : cnt2) {std::cout << b ;}
//		std::cout <<std::endl;
        if (cnt1 == cnt2) {
            return true;
        }
        for (int i = n; i < m; ++i) {
            ++cnt2[s2[i] - 'a'];
            --cnt2[s2[i - n] - 'a'];
//			for (int b : cnt2) {std::cout << b ;}
//			std::cout <<std::endl;
            if (cnt1 == cnt2) {
                return true;
            }
        }
        return false;
    }
};

java代码

public boolean checkInclusion(String s1, String s2) {
        int n = s1.length(), m = s2.length();
        if (n > m) {
            return false;
        }
        int[] cnt1 = new int[26];
        int[] cnt2 = new int[26];
        for (int i = 0; i < n; ++i) {
            ++cnt1[s1.charAt(i) - 'a'];
            ++cnt2[s2.charAt(i) - 'a'];
        }
        if (Arrays.equals(cnt1, cnt2)) {
            return true;
        }
        for (int i = n; i < m; ++i) {
            ++cnt2[s2.charAt(i) - 'a'];
            --cnt2[s2.charAt(i - n) - 'a'];
            if (Arrays.equals(cnt1, cnt2)) {
                return true;
            }
        }
        return false;
    }
3. 题解
  1. 当两个字符串每个字符的个数均相等时,一个字符串才是另一个字符串的排列
  2. 使用两个数组分别表示s1 和s2中子串的各个字符的个数
  3. 使用一个固定长度为 nn 的滑动窗口来维护cnt2,滑动窗口每向右滑动一次,就多统计一次进入窗口的字符,少统计一次离开窗口的字符。然后,判断 cnt1 和 cnt2是否相等,相等就表示找到了是s1排列的子串
  4. vector size设置为26,代表26个字母长度, 【s1[i] - ‘a’ 】表示当前字符下标值,++cnt1[s1[i] - ‘a’] 是给当前下标赋值,理解不了可以看参照下图, 是上述代码中注释掉的输出log

测试代码

Solution so;
	bool ret = so.checkInclusion("ab", "eidoooba");
	std::cout << ret << std::endl;

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值