力扣[LeetCode]-Hot100Java代码实现

力扣[LeetCode]hot100Java代码实现


前言

25.4.18一刷hot100,分享一下每题的多种解法,不定时更新。


一、哈希

1.两数之和

力扣题目链接1.两数之和
给定一个整数数组 nums 和一个整数目标值 target,请你在该数组中找出 和为目标值 target 的那 两个 整数,并返回它们的数组下标。

你可以假设每种输入只会对应一个答案,并且你不能使用两次相同的元素。

你可以按任意顺序返回答案。

输入:nums = [2,7,11,15], target = 9
输出:[0,1]
解释:因为 nums[0] + nums[1] == 9 ,返回 [0, 1] 。

class Solution {
    public int[] twoSum(int[] nums, int target) {
        int[] res = new int[2];
        for(int i =0;i<nums.length;i++){
            int number = target-nums[i];
            res[0]=i;
            for(int j =0;j<nums.length;j++){
                if(number==nums[j]&&i!=j){
                    res[1]=j;
                    return res;
                }
            }
        }
        return res;
    }
}

2.字母异位词分组

力扣题目链接49.字母异位词分组
给你一个字符串数组,请你将 字母异位词 组合在一起。可以按任意顺序返回结果列表。

字母异位词 是由重新排列源单词的所有字母得到的一个新单词。

输入: strs = [“eat”, “tea”, “tan”, “ate”, “nat”, “bat”]
输出: [[“bat”],[“nat”,“tan”],[“ate”,“eat”,“tea”]]

class Solution {
    public List<List<String>> groupAnagrams(String[] strs) {
        HashMap<String, List<String>> res = new HashMap<>();
        
        if(strs.length==0||strs==null){
            return new ArrayList<>();
        }else{
            for(String str:strs){
                char[] chars = str.toCharArray();
                Arrays.sort(chars);
                String key = new String(chars);
                if(!res.containsKey(key)){
                    res.put(key,new ArrayList<>());
                }
                res.get(key).add(str);
            }

            return new ArrayList<>(res.values());
        }
        
    }
}

3.最长连续序列

力扣题目链接128.最长连续序列
给定一个未排序的整数数组 nums ,找出数字连续的最长序列(不要求序列元素在原数组中连续)的长度。

请你设计并实现时间复杂度为 O(n) 的算法解决此问题。

输入:nums = [100,4,200,1,3,2]
输出:4
解释:最长数字连续序列是 [1, 2, 3, 4]。它的长度为 4。

class Solution {
    public int longestConsecutive(int[] nums) {
        Set<Integer> numSet = new HashSet<>();
        for (int num : nums) {
            numSet.add(num);
        }

        int max = 1;
        int current;
        if(nums.length==0){
            return 0;
        }
        for(Integer num: numSet){
            if(!numSet.contains(num-1)){
                current=num;
                int res=1;
                while(numSet.contains(current+1)){
                    res++;
                    current++;
                } 
                max=(max>res)?max:res;
            }
           
            
        }
        return max;
    }
}

二、双指针

4.移动零

力扣题目链接283.移动零
给定一个数组 nums,编写一个函数将所有 0 移动到数组的末尾,同时保持非零元素的相对顺序。

请注意 ,必须在不复制数组的情况下原地对数组进行操作。

输入: nums = [0,1,0,3,12]
输出: [1,3,12,0,0]

class Solution {
    public void moveZeroes(int[] nums) {
        int nozeroIndex=0;
        int count =0;
        for(int i =0;i<nums.length;i++){
            if(nums[i]!=0){
                nums[nozeroIndex]=nums[i];
                nozeroIndex++;
            }else{
                count++;
            }
        }
        for(int i =nums.length-1;i>nums.length-1-count;i--){
            nums[i] = 0;
        }
        
    }
}

5.乘最多水的容器

力扣题目链接11.乘最多水的容器
给定一个长度为 n 的整数数组 height 。有 n 条垂线,第 i 条线的两个端点是 (i, 0) 和 (i, height[i]) 。
找出其中的两条线,使得它们与 x 轴共同构成的容器可以容纳最多的水。
返回容器可以储存的最大水量。
说明:你不能倾斜容器。

输入:[1,8,6,2,5,4,8,3,7]
输出:49
解释:图中垂直线代表输入数组 [1,8,6,2,5,4,8,3,7]。在此情况下,容器能够容纳水(表示为蓝色部分)的最大值为 49。

class Solution {
    public int maxArea(int[] height) {
        int h=0;
        int w=0;
        int maxArea=0;
        int i=0;
        int j=height.length-1;
        while(i<j){
            h=(height[i]<height[j])?height[i]:height[j];
            w=j-i;
            maxArea=(maxArea>h*w)?maxArea:h*w;
            if(height[i]<height[j]){
                i++;
            }else{
                j--;
            }
        }
        return maxArea;
        
    }
}

6.三数之和

力扣题目链接15.三数之和
给你一个整数数组 nums ,判断是否存在三元组 [nums[i], nums[j], nums[k]] 满足 i != j、i != k 且 j != k ,同时还满足 nums[i] + nums[j] + nums[k] == 0 。请你返回所有和为 0 且不重复的三元组。

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

输入:nums = [-1,0,1,2,-1,-4]
输出:[[-1,-1,2],[-1,0,1]]
解释:
nums[0] + nums[1] + nums[2] = (-1) + 0 + 1 = 0 。
nums[1] + nums[2] + nums[4] = 0 + 1 + (-1) = 0 。
nums[0] + nums[3] + nums[4] = (-1) + 2 + (-1) = 0 。
不同的三元组是 [-1,0,1] 和 [-1,-1,2] 。
注意,输出的顺序和三元组的顺序并不重要。

class Solution {
    public List<List<Integer>> threeSum(int[] nums) {
        Arrays.sort(nums);
        List<List<Integer>> res = new ArrayList<>();
        for(int i = 0;i<nums.length;i++){
            
            int j=i+1;
            int last = nums.length-1;
            while(j<last){
                int sum = nums[i]+nums[j]+nums[last];
                if(sum==0){
                    ArrayList<Integer> list=new ArrayList<>();
                    list.add(nums[i]);
                    list.add(nums[j]);
                    list.add(nums[last]);
                    res.add(list);
                    
                    last--;
                    j++;
                }else if(sum>0){
                    last--;
                }else{
                    j++;
                }
            }
        }
        return res;
        
    }
}

7.接雨水

力扣42.接雨水
给定 n 个非负整数表示每个宽度为 1 的柱子的高度图,计算按此排列的柱子,下雨之后能接多少雨水。
在这里插入图片描述

输入:height = [0,1,0,2,1,0,1,3,2,1,2,1]
输出:6
解释:上面是由数组 [0,1,0,2,1,0,1,3,2,1,2,1] 表示的高度图,在这种情况下,可以接 6 个单位的雨水(蓝色部分表示雨水)。

class Solution {
    public int trap(int[] height) {
        int total=0;
        int left=0;
        int right=height.length-1;
        int maxLeft=0;
        int maxRight=0;

        while(left<right){
            if(height[left]<=height[right]){
                total+=Math.max(0,maxLeft-height[left]);
                maxLeft=Math.max(maxLeft,height[left]);
                left++;
            }else{
                total+=Math.max(0,maxRight-height[right]);
                maxRight=Math.max(maxRight,height[right]);
                right--;
            }
        }
        return total;
        
    }
}

三、滑动窗口

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

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

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

class Solution {
    public int lengthOfLongestSubstring(String s) {
        HashMap<Character, Integer> res = new HashMap<>();
        int len=0;
        int left=0;
        for(int i = 0;i<s.length();i++){
            char c = s.charAt(i);
            if(res.containsKey(c)&&left<=res.get(c)){
                left=res.get(c)+1;
            }
            res.put(c,i);
            len=Math.max(len,i-left+1);

        }
        return len;
    }
}

9.找到字符串中所有字母异位词

力扣438.找到字符串中所有字母异位词
给定两个字符串 s 和 p,找到 s 中所有 p 的 异位词 的子串,返回这些子串的起始索引。不考虑答案输出的顺序。

输入: s = “cbaebabacd”, p = “abc”
输出: [0,6]
解释:
起始索引等于 0 的子串是 “cba”, 它是 “abc” 的异位词。
起始索引等于 6 的子串是 “bac”, 它是 “abc” 的异位词。

class Solution {
    public List<Integer> findAnagrams(String s, String p) {
        List<Integer> res = new ArrayList<>();

        if(p.length()>s.length()){
            return res;
        }
        
        
        HashMap<Character, Integer> pMap = new HashMap<>();
        for (char c : p.toCharArray()) {
            pMap.put(c,pMap.getOrDefault(c,0)+1);
        }
        HashMap<Character, Integer> windowMap = new HashMap<>();
        for(int i =0;i<p.length()-1;i++){
            windowMap.put(s.charAt(i),windowMap.getOrDefault(s.charAt(i),0)+1);
        }

        for(int i =p.length()-1;i<s.length();i++){

            windowMap.put(s.charAt(i),windowMap.getOrDefault(s.charAt(i),0)+1);
            if(windowMap.equals(pMap)){
                res.add(i-p.length()+1);
            }
            
            windowMap.put(s.charAt(i-p.length()+1),windowMap.getOrDefault(s.charAt(i-p.length()+1),0)-1);

            if(windowMap.get(s.charAt(i-p.length()+1))==0){
                windowMap.remove(s.charAt(i-p.length()+1));
            }
            
        }
        return res;
        
        
    }
}

10.和为K的子数组

力扣560.和为K的子数组
给你一个整数数组 nums 和一个整数 k ,请你统计并返回 该数组中和为 k 的子数组的个数 。

子数组是数组中元素的连续非空序列。

输入:nums = [1,1,1], k = 2
输出:2

public class Solution {
    public int subarraySum(int[] nums, int k) {
        int count = 0;
        HashMap<Integer,Integer> pre = new HashMap<>();
        pre.put(0,1);
        int currentSum = 0;
        for(int num: nums){
            currentSum+=num;
            if(pre.containsKey(currentSum-k)){
                count+=pre.get(currentSum-k);
            }

            pre.put(currentSum, pre.getOrDefault(currentSum, 0)+1);
        }
        return count;
    }
}

11.滑动窗口最大值

239.滑动窗口最大值
给你一个整数数组 nums,有一个大小为 k 的滑动窗口从数组的最左侧移动到数组的最右侧。你只可以看到在滑动窗口内的 k 个数字。滑动窗口每次只向右移动一位。
返回 滑动窗口中的最大值 。

输入:nums = [1,3,-1,-3,5,3,6,7], k = 3
输出:[3,3,5,5,6,7]
解释:
滑动窗口的位置 最大值
[1 3 -1] -3 5 3 6 7 3
1 [3 -1 -3] 5 3 6 7 3
1 3 [-1 -3 5] 3 6 7 5
1 3 -1 [-3 5 3] 6 7 5
1 3 -1 -3 [5 3 6] 7 6
1 3 -1 -3 5 [3 6 7] 7

优先队列:

class Solution {
    public int[] maxSlidingWindow(int[] nums, int k) {
        int[] res = new int[nums.length-k+1];
        //放nums[i]和i
        PriorityQueue<int[]> queue = new PriorityQueue<>(
            //大的num在前面,同样的num是i大的在前面
            (a,b)->(a[0]!=b[0]?b[0]-a[0]:b[1]-a[1])
        );
        //先放k个
        for(int i=0;i<k;i++){
            queue.offer(new int[]{nums[i],i});
        }
        res[0] = queue.peek()[0];
        for(int i=k;i<nums.length;i++){
            queue.offer(new int[]{nums[i],i});
            //队列放k个,i-k是窗口的左边界
            while(i-k>=queue.peek()[1]){
                queue.poll();
            }
            //队首放着窗口最大的num
            res[i-k+1] = queue.peek()[0];
        }
        return res;

    }
}

双端队列:

class Solution {
   public int[] maxSlidingWindow(int[] nums, int k) {
       int[] res = new int[nums.length-k+1];
       //放没有被移除的i
       Deque<Integer> queue = new LinkedList<>();
       //先放k个
       for(int i=0;i<k;i++){
           //从后往前遍历queue里面的num,如果新的num比他们大,就移除这些
           while(!queue.isEmpty()&&nums[i]>=nums[queue.peekLast()]){
               queue.pollLast();
           }
           queue.offerLast(i);
       }
       res[0] = nums[queue.peekFirst()];
       for(int i=k;i<nums.length;i++){
           while(!queue.isEmpty()&&nums[i]>=nums[queue.peekLast()]){
               queue.pollLast();
           }
           queue.offerLast(i);
           //i-k是窗口的左边界
           while(i-k>=queue.peekFirst()){
               queue.pollFirst();
           }
           //队首放着窗口最大的num的i
           res[i-k+1] = nums[queue.peekFirst()];
       }
       return res;

   }
}

12.最小覆盖子串

76.最小覆盖子串
给你一个字符串 s 、一个字符串 t 。返回 s 中涵盖 t 所有字符的最小子串。如果 s 中不存在涵盖 t 所有字符的子串,则返回空字符串 “” 。
注意:
对于 t 中重复字符,我们寻找的子字符串中该字符数量必须不少于 t 中该字符数量。
如果 s 中存在这样的子串,我们保证它是唯一的答案。

public String minWindow(String s, String t) {
        int left=0,right=0;
        int minlen = s.length()+1;
        int ansL=-1,ansR=0;
        int form = 0;//保存当前已经匹配的字符数量
        //A-Z,6个其他字符,a-z,26+6+26=58
        int[] tList = new int[58];
        for(char c:t.toCharArray()){
            tList[c-'A']++;
        }
        while(right<s.length()&&left<=right){
            int cs = s.charAt(right)-'A';
            if(tList[cs]>0){
                form++;
            }
            tList[cs]--;
            right++;
            //匹配到了
            while(form==t.length()){
                //更新最小值
                if(right-left<minlen){
                    ansL = left;
                    ansR = right;
                    minlen = right-left;
                }
                //缩小左边界
                int index = s.charAt(left)-'A';
                tList[index]++;
                if(tList[index]>0){
                    form--;
                }
                left++;
            }
        }
        return ansL==-1 ? "" : s.substring(ansL, ansR);
    }

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值