方法一:暴力求解(效率差):
使用两个 for 循环,一个 for 循环固定一个数字比如 m,另一个 for 循环从 m 的下一个元素开始累加,当和大于等于 s 的时候终止内层循环,顺便记录下最小长度
public int minSubArrayLen(int s, int[] nums) {
int min = Integer.MAX_VALUE;
for (int i = 0; i < nums.length; i++) {
int sum = nums[i];
if (sum >= s)
return 1;
for (int j = i + 1; j < nums.length; j++) {
sum += nums[j];
if (sum >= s) {
min = Math.min(min, j - i + 1);
break;
}
}
}
return min == Integer.MAX_VALUE ? 0 : min;
}
方法二:滑动窗口,使用双指针,left和right,分别用来向右缩小窗口和向右扩大窗口
思路:遇到题目求最小,可思考先预设一个最大值,然后不断更新
窗口包含数值总和大了就向右缩小窗口,小了就向右扩展窗口,不断试错,直至找到最小窗口,并且使所有值加起来超不过target
注意前后顺序
class Solution {
public int minSubArrayLen(int target, int[] nums) {
int left = 0;
int sum = 0;
int result = Integer.MAX_VALUE;//让窗口最大,这样就能不断更新最小值窗口
for(int right = 0;right < nums.length ;right++){
sum += nums[right];
while(sum >= target){
result = Math.min(result, right - left + 1);//让窗口永远保持最小
sum -= nums[left++];//左侧索引前移
}
}
//依照案例,如果所有值加起来都小于target,返回0,也就是MAX_VALUE一直都没变过
return result == Integer.MAX_VALUE ? 0 : result;
}
}
class Solution {
public List<Integer> findAnagrams(String s, String p) {
List<Integer> ans = new ArrayList<>();
int m = s.length();
int n = p.length();
if (m < n) {
// 如果s没p长,直接返回空列表
return ans;
}
int[] sCnt = new int[26];
int[] pCnt = new int[26];
for (int i = 0; i < n; i++) {
sCnt[s.charAt(i) - 'a']++;
pCnt[p.charAt(i) - 'a']++;
}
if (Arrays.equals(sCnt, pCnt)) {
// 初始窗口就相等
ans.add(0);
}
for (int i = 0; i < m - n; i++) {
// 窗口右移
sCnt[s.charAt(i) - 'a']--;
sCnt[s.charAt(i + n) - 'a']++;
if (Arrays.equals(sCnt, pCnt)) {
ans.add(i + 1);
}
}
return ans;
}
}
public String minWindow( String s, String t ) {
String res = "";
if ( t.length() > s.length() ) {
return res;
}
HashMap<Character, Integer> need = new HashMap<>();
HashMap<Character, Integer> window = new HashMap<>();
for ( int i = 0; i < t.length(); i++ ) {
char ch = t.charAt( i );
need.put( ch, need.getOrDefault( ch, 0 ) + 1 );
}
int l = 0;
int r = 0;
int valid = 0;
int len = Integer.MAX_VALUE;
int start = 0;
while ( r < s.length() ) {
char ch = s.charAt( r );
r++;
if ( need.containsKey( ch ) ) {
window.put( ch, window.getOrDefault( ch, 0 ) + 1 );
if ( window.get( ch ).equals( need.get( ch ) ) ) {
valid++;
}
}
// 判断左侧窗口是否要收缩
while ( valid == need.size() ) {
// 在这里更新最小覆盖子串
if ( r - l < len ) {
start = l;
len = r - l;
}
// d 是将移出窗口的字符
char d = s.charAt( l );
// 左移窗口
l++;
// 进行窗口内数据的一系列更新
if ( need.containsKey( d ) ) {
if ( window.get( d ).equals( need.get( d ) ) ) {
valid--;
}
window.put( d, window.get( d ) - 1 );
}
}
}
return len == Integer.MAX_VALUE ? "" : s.substring( start, start+len );
}
要注意什么时候向右扩大窗口,什么时候向右缩小窗口,什么时候结算窗口内的信息,如何更新窗口内的信息
class Solution {
public boolean checkInclusion(String s1, String s2) {
int l=0;
int r=0;
int []s1arr=new int[26];
int []s2arr=new int[26];
for(int i=0;i<s1.length();i++){
s1arr[s1.charAt(i)-'a']++;
}
while(r<s2.length()){
s2arr[s2.charAt(r)-'a']++;
if(r-l+1==s1.length()){
if(equalS1S2(s1arr,s2arr)) {
return true;
}else{
s2arr[s2.charAt(l)-'a']--;
l++;
}
}
r++;//r++位置要放好,不能直接放在s2arr[s2.charAt(r)-'a']++;下面
}
return false;
}
public boolean equalS1S2( int[] s1,int[] s2){
for(int i=0;i<s1.length;i++){
if(s1[i]!=s2[i])return false;
}
return true;
}
}
使用set,让left每次加一
/*时间复杂度:O(2n) = O(n),最坏的情况是 left 和 right 都遍历了一遍字符串*/
/*空间复杂度:O(n)*/
/*https://leetcode-cn.com/problems/longest-substring-without-repeating-characters/solution/jian-dan-yi-dong-javac-pythonjshua-dong-bff20/*/
public int lengthOfLongestSubstring2(String s) {
int n = s.length();
if (n <= 1) return n;
int maxLen = 1;
int left = 0, right = 0;
/*使用set集合记录窗口中出现的字符,这样可以保证 不重复,
*如果窗口中不包含右指针指向的字符,就把它加入set(并记录窗口最大值 ),如果存在就移除 ,并将left指针++,每次移动一次*/
Set<Character> window = new HashSet<>();
while (right < n) {
char rightChar = s.charAt(right);
while (window.contains(rightChar)) {
window.remove(s.charAt(left));
left++;
}
maxLen = Math.max(maxLen, right - left + 1);
window.add(rightChar);
right++;
}
return maxLen;
}
使用map,记录每个字符的索引,遇到重复字符时,直接跳到 重复字符的下一个 位置
/*上面的方法,出现重复字符时,是一个一个字符的缩小窗口
*可以通过map记录每个字符在字符串中出现的位置,当遇到重复字符时,把left指针跳到重复字符的下一个位置 */
/*/*力扣3,评论区
* https://leetcode-cn.com/problems/longest-substring-without-repeating-characters/solution/wu-zhong-fu-zi-fu-de-zui-chang-zi-chuan-by-leetc-2
* */*/
public static int lengthOfLongestSubstringWithoutRepeatingCharacters(String s) {
int len = s.length();
Map<Character, Integer> index = new HashMap<>();
int max = 0;
int left = 0;
for (int right = 0; right < len; right++) {
char c = s.charAt(right);
if (index.containsKey(c)) {
int lastIndex = index.get(c);
if (lastIndex + 1 > left) {
left = lastIndex + 1;
}
}
//因为左指针已经跳到重复字符的下一个位置了,当前右指针指向的字符跟去掉的字符一样,所以需要在map中更新一下位置
index.put(c, right);
max = Math.max(max, right - left + 1);
}
return max;
}
因篇幅问题不能全部显示,请点此查看更多更全内容
Copyright © 2019- azee.cn 版权所有 赣ICP备2024042794号-5
违法及侵权请联系:TEL:199 1889 7713 E-MAIL:2724546146@qq.com
本站由北京市万商天勤律师事务所王兴未律师提供法律服务