双指针

76 阅读1分钟

#盛最多水的容器(Container With Most Water)。

题目描述:

给定一个非负整数数组height,每个元素表示一个高度。找出两个高度,其间的距离与两个高度的最小值的乘积最大。也就是说,找到一对i和j,使得i < j且(height[i], height[j])可以盛水的容器面积最大。

示例:

输入: [1,8,6,2,5,4,8,3,7] 输出: 49

public int maxArea(int[] height) {
    int left = 0, right = height.length - 1;
    int maxArea = 0;
    while (left < right) {
        int area = Math.min(height[left], height[right]) * (right - left);
        maxArea = Math.max(maxArea, area);
        if (height[left] < height[right]) {
            left++;
        } else {
            right--;
        }
    }
    return maxArea;
}

这道题可以使用双指针来解决。我们可以设置两个指针,一个指向数组的开头,一个指向数组的结尾。然后我们计算当前指针指向的两个高度的最小值乘以它们之间的距离,得到当前容器的面积。接着我们将较小的那个高度的指针向内移动,因为如果我们移动高度较大的指针,那么容器的面积只会变小。我们不断地移动指针,直到两个指针相遇为止,期间记录每次计算的容器面积的最大值即可。

#三数之和(3Sum)。

题目描述:

给定一个包含n个整数的数组nums,判断nums中是否存在三个元素a,b,c,使得a + b + c = 0?找出所有满足条件且不重复的三元组。

注意:答案中不可以包含重复的三元组。

示例:

输入:nums = [-1,0,1,2,-1,-4] 输出:[[-1,-1,2],[-1,0,1]]

解题思路:

这道题可以使用双指针来解决。首先我们对数组进行排序,然后我们枚举数组中的每一个元素作为a,然后在剩余的元素中使用双指针找到满足b + c = -a的所有组合。由于题目中要求不重复的三元组,所以我们需要注意避免重复的情况。

public List<List<Integer>> threeSum(int[] nums) {
    List<List<Integer>> result = new ArrayList<>();
    Arrays.sort(nums);
    int n = nums.length;
    for (int i = 0; i < n - 2; i++) {
        if (i > 0 && nums[i] == nums[i - 1]) { // 避免重复
            continue;
        }
        int left = i + 1, right = n - 1;
        while (left < right) {
            int sum = nums[i] + nums[left] + nums[right];
            if (sum == 0) {
                result.add(Arrays.asList(nums[i], nums[left], nums[right]));
                left++;
                right--;
                while (left < right && nums[left] == nums[left - 1]) { // 避免重复
                    left++;
                }
                while (left < right && nums[right] == nums[right + 1]) { // 避免重复
                    right--;
                }
            } else if (sum < 0) {
                left++;
            } else {
                right--;
            }
        }
    }
    return result;
}

最长无重复子串

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

示例:

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


public int lengthOfLongestSubstring(String s) {
    int n = s.length();
    Set<Character> set = new HashSet<>();
    int ans = 0, i = 0, j = 0;
    while (i < n && j < n) {
        if (!set.contains(s.charAt(j))) {
            set.add(s.charAt(j++));
            ans = Math.max(ans, j - i);
        } else {
            set.remove(s.charAt(i++));
        }
    }
    return ans;
}

这个算法使用了滑动窗口的思想,维护了一个窗口,窗口内的字串是不含重复字符的。当窗口右端点 j 指向的字符不在窗口中时,将其加入窗口,并更新最长子串长度;当窗口中已经有了该字符时,将窗口左端点 i 向右移动,直到窗口中不包含该字符。这样可以保证窗口内的子串不含重复字符,且能够找到最长的子串。时间复杂度为 O(n)。