Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Two Pointer问题总结 #14

Open
RubyLouvre opened this issue Jul 19, 2019 · 7 comments
Open

Two Pointer问题总结 #14

RubyLouvre opened this issue Jul 19, 2019 · 7 comments

Comments

@RubyLouvre
Copy link
Owner

RubyLouvre commented Jul 19, 2019

209. Minimum Size Subarray Sum

Given an array of n positive integers and a positive integer s, find the minimal length of a contiguous subarray of which the sum ≥ s. If there isn't one, return 0 instead.

Example:

Input: s = 7, nums = [2,3,1,2,4,3]
Output: 2
Explanation: the subarray [4,3] has the minimal length under the problem constraint.
Follow up:
If you have figured out the O(n) solution, try coding another solution of which the time complexity is O(n log n).

var minSubArrayLen = function(s, nums) {
        var left = 0;
        var right = -1;	//把[left, right]区间看作是一个滑动窗口,初始时滑动窗口中没有元素故right = -1
        var sum = 0;
        var len = nums.length + 1;//n + 1比整个数组的长度还大,但要注意这个值其实是取不到的
        while(left < nums.length) {
            if(right + 1 < nums.length && sum < s) {//当sum < s时,滑动窗口向右延伸使窗口内的值变大
                right++;
                sum += nums[right];
            }else {	//当sum >= s时,滑动窗口left增大,使窗口向右缩进使得窗口内的值变小
                sum -= nums[left];
                left++;
            }
            if(sum >= s) {
                console.log(nums.slice(left, right+1))
                len = Math.min(len, right - left + 1);
            }
        }
        if(len == nums.length + 1) {
            return 0;
        }else {
            return len;
        }
};

image

var minSubArrayLen = function(s, nums) {
     if(!nums.length){
         return 0
     }
     var left = 0, right = 0, sum = 0, minLen = Infinity, len = 0
      while (right < nums.length || left < nums.length) {//确定循环条件,left, right都往右走
        //先让right,直到它满足条件
        if (sum < s && right < nums.length) {
          sum += nums[right]
          right++
          len = right - left
        } else {
         if (sum >= s && minLen > len) {
            minLen = len
          }
          //上面right < nums.length的条件会强制它进入下面的分支
          sum -= nums[left]
          left++
          len--;
        }
      }
     // console.log(minLen)
      return minLen == Infinity ? 0: minLen
};

简化判定条件

 var minSubArrayLen = function (s, nums) {
      if (!nums.length) {
        return 0
      }
      var left = 0, right = 0, sum = 0, minLen = Infinity, len = 0
      while (left < nums.length) {//确定循环条件,left, right都往右走
        //先让right,直到它满足条件
        if (sum < s && right < nums.length) {
          sum += nums[right]
          right++
          len = right - left
        } else {
          if (sum >= s && minLen > len) {
            minLen = len
          }
          //上面right < nums.length的条件会强制它进入下面的分支
          sum -= nums[left]
          left++
          len--;
          if (sum >= s && minLen > len) {
            minLen = len
          }
        }
      }
      // console.log(minLen)
      return minLen == Infinity ? 0 : minLen
    };

还有这样的骚操作

var minSubArrayLen = function (s, nums) {
        var len = nums.length;
        var res = len + 1, left = 0, sum = 0;
        for (var right = 0; right < len; right++) {
          sum += nums[right];
          while (left <= right && sum >= s) {
            res = Math.min(res, right - left + 1);
            sum -= nums[left++];
          }
        }
        return res == len + 1 ? 0 : res;
      };
@RubyLouvre
Copy link
Owner Author

167. Two Sum II - Input array is sorted

Given an array of integers that is already sorted in ascending order, find two numbers such that they add up to a specific target number.

The function twoSum should return indices of the two numbers such that they add up to the target, where index1 must be less than index2.

Note:

Your returned answers (both index1 and index2) are not zero-based.
You may assume that each input would have exactly one solution and you may not use the same element twice.
Example:

Input: numbers = [2,7,11,15], target = 9
Output: [1,2]
Explanation: The sum of 2 and 7 is 9. Therefore index1 = 1, index2 = 2.

var twoSum = function(numbers, target) {
  
    var left = 0, right = numbers.length-1;
    while(left < right){
        if(numbers[left] + numbers[right] == target){
            return [left+1, right+1]
        }else if(numbers[left] + numbers[right] > target){
            right --
        }else{
            left++
        }
    }
    return []
    
};

@RubyLouvre
Copy link
Owner Author

RubyLouvre commented Jul 19, 2019

763. Partition Labels

A string S of lowercase letters is given. We want to partition this string into as many parts as possible so that each letter appears in at most one part, and return a list of integers representing the size of these parts.

Example 1:
Input: S = "ababcbacadefegdehijhklij"
Output: [9,7,8]
Explanation:
The partition is "ababcbaca", "defegde", "hijhklij".
This is a partition so that each letter appears in at most one part.
A partition like "ababcbacadefegde", "hijhklij" is incorrect, because it splits S into less parts.

Note:

S will have length in range [1, 500].
S will consist of lowercase letters ('a' to 'z') only.

function partitionLabels( s) {
      var ans = []
		if (!s.length){
      return ans;
    } 
		// 依次对数组进行遍历, 先找到相应的数据的最后一个位置, 构成区间, 然后查看区间内的元素, 随时扩充区间.
		// 若找到了 就保存下来, 然后继续从下一个上一个区间的最后一个+1的位置继续进行
		for (var i = 0; i < s.length;) {
			// 最开始确定的区间 [start, end] 这个end可以扩充
			var start = i;
			// 没有判断这个end是否存在
			var end = s.lastIndexOf(s[start]);
			if (end == -1) {
				end = start;
			}
			// 当end不存在的时候, 会返回一个很大的数字. 
			// 在子区间内继续进行扩充
			for (var j = start + 1; j <= end; j++) {
				var lastPos = s.lastIndexOf(s[j]);
				// 如果能找到这个字母的最后一个位置
				if (lastPos != -1 && lastPos > end) {
					// 这个是最终的end
					end = lastPos;
				}
			}
      // 要记录被扩大的区间
      console.log(s.slice(start, end+1))
			ans.push(end - start + 1);
			// 对i进行更新
			i = end + 1;
		}
    return ans
}
console.log( partitionLabels('ababcbacadefegdehijhklij') )
console.log( partitionLabels('abbcdbyyuiu') )

@RubyLouvre
Copy link
Owner Author

这道题给了我们一个字符串S,然我们将其尽可能多的分割为子字符串,条件是每种字符最多只能出现在一个子串中。比如题目汇总的例子,字符串S中有多个a,这些a必须只能在第一个子串中,再比如所有的字母e值出现在了第二个子串中。那么这道题的难点就是如何找到字符串的断点,即拆分成为子串的位置。我们仔细观察题目中的例子,可以发现一旦某个字母多次出现了,那么其最后一个出现位置必须要在当前子串中,字母a,e,和j,分别是三个子串中的结束字母。所以我们关注的是每个字母最后的出现位置,我们可以使用一个 HashMap 来建立字母和其最后出现位置之间的映射,那么对于题目中的例子来说,我们可以得到如下映射:

a -> 8
b -> 5
c -> 7
d -> 14
e -> 15
f -> 11
g -> 13
h -> 19
i -> 22
j -> 23
k -> 20
l -> 21

建立好映射之后,就需要开始遍历字符串S了,我们维护一个 start 变量,是当前子串的起始位置,还有一个 last 变量,是当前子串的结束位置,每当我们遍历到一个字母,我们需要在 HashMap 中提取出其最后一个位置,因为一旦当前子串包含了一个字母,其必须包含所有的相同字母,所以我们要不停的用当前字母的最后一个位置来更新 last 变量,只有当i和 last 相同了,即当 i = 8 时,当前子串包含了所有已出现过的字母的最后一个位置,即之后的字符串里不会有之前出现过的字母了,此时就应该是断开的位置,我们将长度9加入结果 res 中,同理类推,我们可以找出之后的断开的位置,参见代码如下:

function partitionLabels( s) {
      var res = [], n = s.length
		if (!n){
      return res;
    } 
    var hash = {}
    for(var i = 0; i< n; i++){
       hash[s[i]] = i
    }
    var last = 0, start = 0
    for (var i = 0; i < n; ++i) {
        last = Math.max(last, hash[s[i]]);
        if (i == last) {
            res.push(i - start + 1);
            start = i + 1;
        }
    }
    return res;
}

console.log( partitionLabels('ababcbacadefegdehijhklij') )
console.log( partitionLabels('abbcdbyyuiu') )

@RubyLouvre
Copy link
Owner Author

  1. Subarray Product Less Than K

https://blog.csdn.net/excellentlizhensbfhw/article/details/82597006

function numSubarrayProductLessThanK(nums, k) {
    var n = nums.length
		if (n < 1 || k <= 1){
      return 0;
    } 
    var count = 0, left = 0, multiResult = 1
    for (var right = 0; right < n; right++) {
        multiResult *= nums[right];
        while( multiResult >= k){
          multiResult /= nums[left]
          left+=1 //用于确定滑动窗口的最左边界
        }
        count += right - left +1 //累加子数组个数        
    }
    return count;
}

console.log( numSubarrayProductLessThanK([10,5,2,6], 100) )

@RubyLouvre
Copy link
Owner Author

RubyLouvre commented Jul 19, 2019

424. Longest Repeating Character Replacement

Given a string that consists of only uppercase English letters, you can replace any letter in the string with another letter at most k times. Find the length of a longest substring containing all repeating letters you can get after performing the above operations.

Note:
Both the string's length and k will not exceed 104.

Example 1:

Input:
s = "ABAB", k = 2

Output:
4

Explanation:
Replace the two 'A's with two 'B's or vice versa.
Example 2:

Input:
s = "AABABBA", k = 1

Output:
4

Explanation:
Replace the one 'A' in the middle with 'B' and form "AABBBBA".
The substring "BBBB" has the longest repeating letters, which is 4.

定义一段区间内出现次数最多的字符为“优势字符”
维护有效区间[p1, p2],使得区间内除“优势字符”外的其余字符个数不大于k
时间复杂度O(m * n),其中m为字母个数, n为字符串长度

var characterReplacement = function(nums, k) {
     var n = nums.length
     var hash = {}, left = 0, right = 0, maxCount = 0,res = 0
    for ( ; right < n; right++) {
        var c = nums[right];
        hash[c] = !hash[c] ? 1 : hash[c]+1;
        maxCount = Math.max(maxCount, hash[c]) //得到当前优势的字符
        if(right - left + 1 - maxCount > k){
          hash[nums[left]] --;
          left++
        }
        res = Math.max(res, right - left+1)       
    }
    return res;
};

@RubyLouvre
Copy link
Owner Author

567. Permutation in String

Given two strings s1 and s2, write a function to return true if s2 contains the permutation of s1. In other words, one of the first string's permutations is the substring of the second string.

Example 1:

Input: s1 = "ab" s2 = "eidbaooo"
Output: True
Explanation: s2 contains one permutation of s1 ("ba").
Example 2:

Input:s1= "ab" s2 = "eidboaoo"
Output: False

Note:

The input strings only contain lower case letters.
The length of both given strings is in range [1, 10,000].

 function checkInclusion(s1, s2) {
      var hash1 = new Array(26).fill(0);
      var hash2 = new Array(26).fill(0);
      for (var i = 0; i < s1.length; i++) {
        hash1[s1.charCodeAt(i) - 97]++;
      }
      var left = 0, right = 0
      while (right < s2.length) {
        hash2[s2.charCodeAt(right) - 97]++
        if (hash1 + '' === hash2 + '') {
          return true;
        }
        right++
        if (right - left + 1 > s1.length) {
          hash2[s2.charCodeAt(left) - 97]--;
          left++
        }
      }
      return false
    }

    console.log(checkInclusion('aa', "aa"))
    console.log(checkInclusion('ab', "eidbaooo"))
    console.log(checkInclusion('bdi', "eidboaoo"))
    console.log(checkInclusion('abb', "eidbgaooo"))

https://leetcode.com/problems/permutation-in-string/discuss/102590/8-lines-slide-window-solution-in-Java

@RubyLouvre
Copy link
Owner Author

  1. Minimum Window Substring

Given a string S and a string T, find the minimum window in S which will contain all the characters in T in complexity O(n).

Example:

Input: S = "ADOBECODEBANC", T = "ABC"
Output: "BANC"
Note:

If there is no such window in S that covers all characters in T, return the empty string "".
If there is such window, you are guaranteed that there will always be only one unique minimum window in S.

function minWindow(s, t) {
      if (!s || !t) {
        return ''
      }
      var tmap = new Array(128 - 65).fill(0)
      function getIndex(a, i) {
        return a.charCodeAt(i) - 65
      }
      for (var i = 0; i < t.length; i++) {
        var c = getIndex(t, i)
        ++tmap[c]
      }

      var res = "", counts = 0, minwin = Infinity, left = 0;
      for (var right = 0; right < s.length; right++) {
        var r = getIndex(s, right)
        --tmap[r]; //碰到重复的减去
        if (tmap[r] >= 0) {
          ++counts;//如果只有一个就相加
        }
        //刚好相等
        while (counts >= t.length) {
          if (minwin > right - left + 1) {
            minwin = right - left + 1;
            res = s.substr(left, minwin);
          }
          var l = getIndex(s, left)
          if (tmap[l] >= 0) { //太长了
            --counts;
          }
          ++tmap[l];
          ++left;
        }
      }
      return res;

    }
    minWindow("adobecodebanc", "abc")

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant