力扣爆刷第84天之hot100五连刷6-10

本文介绍了力扣编程平台上的五个热门LeetCode问题,涉及三数之和、接雨水、无重复字符的最长子串、字母异位词检测和和为K的子数组,主要展示了使用滑动窗口、哈希表等技术的解决方案。
摘要由CSDN通过智能技术生成

力扣爆刷第84天之hot100五连刷6-10

一、15. 三数之和

题目链接:https://leetcode.cn/problems/3sum/description/?envType=study-plan-v2&envId=top-100-liked
思路:三数之和和两数之和类似都是使用双指针进行操作,只不过nums数组内包含重复元素,需要考虑去重的操作,先排序,然后外层一个for内层双指针即可完成遍历,完成去重有两步。
一步: if (i > 0 && nums[i] == nums[i-1]) continue;杜绝相同的nums[i]。
二步:当nums[j]+nums[k]==nums[i]时,务必保证nums[j]和nums[k]不再重复。

while(j < k && nums[j] == nums[j+1]) j++;
while(j < k && nums[k] == nums[k-1]) k--;
j++;
k--;
class Solution {
    public List<List<Integer>> threeSum(int[] nums) {
        List<List<Integer>> array = new ArrayList<>();
        Arrays.sort(nums);
        int len = nums.length;
        for(int i = 0; i < len-2; i++) {
            if (nums[i] > 0) break;
            if (i > 0 && nums[i] == nums[i-1]) continue;
            int j = i+1, k = len-1;
            while(j < k) {
                int temp = nums[i] + nums[j] + nums[k];
                if(temp == 0) {
                    List<Integer> list = new ArrayList<>();
                    list.add(nums[i]);
                    list.add(nums[j]);
                    list.add(nums[k]);
                    array.add(list);
                    while(j < k && nums[j] == nums[j+1]) j++;
                    while(j < k && nums[k] == nums[k-1]) k--;
                    j++;
                    k--;
                }else if(temp < 0) {
                    j++;
                }else {
                    k--;
                }
            }
        }
        return array;
    }
}

二、42. 接雨水

题目链接:https://leetcode.cn/problems/trapping-rain-water/description/?envType=study-plan-v2&envId=top-100-liked
思路:接雨水是典型的单调栈问题,只需要构造出来凹型即可,也就是栈内,自栈底到栈顶是递减的,当遇到大于栈顶的元素时,就弹出栈顶,此时栈顶即为凹槽,然后计算面积即可。

class Solution {
   public int trap(int[] height) {
       Deque<Integer> stack = new LinkedList<>();
       int sum = 0;
       for(int i = 0; i < height.length; i++) {
           while(!stack.isEmpty() && height[stack.peek()] < height[i]) {
               int mid = stack.pop();
               if(!stack.isEmpty()) {
                   int h = Math.min(height[i], height[stack.peek()]) - height[mid];
                   int w = i - stack.peek() - 1; 
                   sum += h * w;
               }
           }
           stack.push(i);
       }
       return sum;
    }
}

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

题目链接:https://leetcode.cn/problems/longest-substring-without-repeating-characters/description/?envType=study-plan-v2&envId=top-100-liked
思路:如s = “abcabcbb” 长度为3,典型的滑动窗口,使用set维护不重复的子串,每次新加入元素后,更新最大长度,如果遇到重复元素,则开始缩小窗口,直到当前元素不重复,才继续开始扩大窗口。

class Solution {
  public int lengthOfLongestSubstring(String s) {
        int max = 0;
        Set<Character> set = new HashSet<>();
        int slow = 0;
        for(int i = 0; i < s.length(); i++) {
            while(set.contains(s.charAt(i))) {
                set.remove(s.charAt(slow));
                slow++;
            }
            set.add(s.charAt(i));
            max = Math.max(max, set.size());
        }
        return max;
    }
}

四、438. 找到字符串中所有字母异位词

题目链接:https://leetcode.cn/problems/find-all-anagrams-in-a-string/description/?envType=study-plan-v2&envId=top-100-liked
思路:一看是异位词基本上就得使用set或map来处理,字符串的长度又巨长,10的4次方,常规遍历自然超时,需要使用双指针去掉一层循环,即使用滑动窗口,维护好字符串窗口,开始时扩大窗口,顺便记录标记值,当窗口达到p字符串长度时,进行判断,看看标记值是否符合,然后缩减窗口,这样一次循环结束。
滑动窗口模板:

/* 滑动窗口算法框架 */
void slidingWindow(String s) {
    // 用合适的数据结构记录窗口中的数据
    HashMap<Character, Integer> window = new HashMap<>();

    int left = 0, right = 0;
    while (right < s.length()) {
        // c 是将移入窗口的字符
        char c = s.charAt(right);
        window.put(c, window.getOrDefault(c, 0) + 1);
        // 增大窗口
        right++;
        // 进行窗口内数据的一系列更新
        ...

        /*** debug 输出的位置 ***/
        // 注意在最终的解法代码中不要 print
        // 因为 IO 操作很耗时,可能导致超时
        System.out.printf("window: [%d, %d)\n", left, right);
        /********************/

        // 判断左侧窗口是否要收缩
        while (left < right && window needs shrink) {
            // d 是将移出窗口的字符
            char d = s.charAt(left);
            window.put(d, window.get(d) - 1);
            // 缩小窗口
            left++;
            // 进行窗口内数据的一系列更新
            ...
        }
    }
}

题解:

class Solution {
    public List<Integer> findAnagrams(String s, String p) {
        List<Integer> list = new ArrayList<>();
        int sLen = s.length(), pLen = p.length();
        if(pLen > sLen) return list;
        Map<Character, Integer> need = new HashMap<>();
        Map<Character, Integer> window = new HashMap<>();
        for(char c : p.toCharArray()) {
            need.put(c, need.getOrDefault(c, 0)+1);
        }
        int left = 0, right = 0, valid = 0;
        while(right < sLen) {
            char rc = s.charAt(right);
            right++;
            if(need.containsKey(rc)) {
                window.put(rc, window.getOrDefault(rc, 0)+1);
                if(window.get(rc).equals(need.get(rc))) {
                    valid++;
                }
            }
            if(right - left == pLen) {
                if(valid == need.size()) {
                    list.add(left);
                }
                char lc = s.charAt(left);
                left++;
                if(need.containsKey(lc)) {
                    if(window.get(lc).equals(need.get(lc))) {
                        valid--;
                    }
                    window.put(lc, window.get(lc)-1);
                }
            }
        }
        return list;
    }
}

五、560. 和为 K 的子数组

题目链接:https://leetcode.cn/problems/subarray-sum-equals-k/description/?envType=study-plan-v2&envId=top-100-liked
思路:求和为k的子数组,其实就是前缀和,和使用前缀和数组的题目有点像,但是为了少一层for,把原本要存入前缀和数组的值,都存进了hashmap,然后只需要用preSum - k 去map中寻找value即可。

class Solution {
    public int subarraySum(int[] nums, int k) {
        Map<Integer, Integer> map = new HashMap<>();
        map.put(0, 1);
        int count = 0, preSum = 0;
        for(int i = 0; i < nums.length; i++) {
            preSum += nums[i];
            if(map.containsKey(preSum - k)) {
                count += map.get(preSum - k);
            }
            map.put(preSum, map.getOrDefault(preSum, 0)+1);
        }
        return count;
    }
}
  • 9
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

当年拼却醉颜红

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值