力扣hot100刷题day1(哈希&双指针)

二刷:

(最长连续序列,三数之和):大循环外层,一个一个元素判断,具体的判断逻辑使用到哈希或双指针

接雨水:双指针法再看

哈希统计频数  或  去重--hot100堆的题

一:哈希

1.两数之和

哈希表,差值在数组里

class Solution {
    public int[] twoSum(int[] nums, int target) {
         HashMap<Integer,Integer> set =new HashMap<>();
         for (int i = 0; i < nums.length; i++) {
            if (set.containsKey(target-nums[i])) {
                return new int[]{set.get(target-nums[i]),i};
            }
            set.put(nums[i], i);
         }
         return new int[]{0,0};
    }
}

2.字母异位词分组

遍历字符串数组,对于每个字符串,将其转换为字符数组,并对字符数组进行排序。 然后将排序后的字符数组转换为字符串,并将其作为键,将原始字符串添加到对应键的值列表中。 最后将哈希表中的值列表转换为结果列表返回。

class Solution {
    public List<List<String>> groupAnagrams(String[] strs) {
        HashMap<String,List<String>> map =new HashMap<>();
        for (String str : strs) {
            char[] arr=str.toCharArray();
            Arrays.sort(arr);
            //将排序后的字符串作为哈希表中的key值
            String key = String.valueOf(arr);
            List<String> result=new ArrayList<>();
            if (!map.containsKey(key)) {
                map.put(key, result);
            }
            map.get(key).add(str);
        }
       return new ArrayList(map.values());
       
    }
}

Map通常用于存储键值对,其中每个键映射到一个值。当我们尝试访问一个不存在的键时,Map会返回null值。如果map的value值为空,就会抛出空指针异常。

getOrDefault()方法的语法如下:

该方法接受两个参数:要查找的键和默认值。如果键存在,则返回与该键关联的值,否则返回指定的默认值。

(无key键存在,返回指定的默认值,

List<String> result= map.getOrDefault(key, new ArrayList<String>());

map.getOrDefault(key, new ArrayList<String>());获取key的值,是new ArrayList<String>(),

存在 result中)

class Solution {
    public List<List<String>> groupAnagrams(String[] strs) {
        HashMap<String,List<String>> map =new HashMap<>();
        for (String str : strs) {
            char[] arr=str.toCharArray();
            Arrays.sort(arr);
            //将排序后的字符串作为哈希表中的key值
            String key = String.valueOf(arr);
            //getOrDefault避免空指针异常
            List<String> result= map.getOrDefault(key, new ArrayList<String>());
            result.add(str);
            map.put(key, result);
        }
       return new ArrayList(map.values());
       
    }
}

3.最长连续序列

class Solution {
    public int longestConsecutive(int[] nums) {
        HashMap<Integer,Integer> map = new HashMap<>();
        for (int i = 0; i < nums.length; i++) {
            map.put(nums[i], i);
        }
        int result=0;
        for (int num : nums) {
            int mid=num;
            if (!map.containsKey(mid-1)) {
                while (map.containsKey(mid+1)) {
                    mid++;
                }
            }
            result=Math.max(result, mid-num+1);
        }
        return result;
    }
}

Set set=new HashSet();

class Solution {
    public int longestConsecutive(int[] nums) {
        Set<Integer> set =new HashSet<>();
        for (int num : nums) {
            set.add(num);
        }
        int result=0;
        for (int num : nums) {
            int cur=num;
            if (!set.contains(cur-1)) {
                while (set.contains(cur+1)) {
                    cur++;
                }
            }
            result=Math.max(result, cur-num+1);
        }
        return result;
    }
}

1050ms,没提升。

前面都搞错了,建立了哈希set,但是后面查询还是在nums数组里查,中间那个for写错了。

class Solution {
    public int longestConsecutive(int[] nums) {
        Set<Integer> set =new HashSet<>();
        for (int num : nums) {
            set.add(num);
        }
        int result=0;
        for (Integer num : set) {
            int cur=num;
            if (!set.contains(cur-1)) {
                while (set.contains(cur+1)) {
                    cur++;
                }
            }
            result=Math.max(result, cur-num+1);
        }
        return result;
    }
}

二:双指针

双指针法(快慢指针法):

通过一个快指针和慢指针在一个for循环下完成两个for循环的工作。定义快慢指针:

快指针:寻找新数组的元素 ,新数组就是不含有目标元素的数组
慢指针:指向更新 新数组下标的位置

解题:(1)同一端出发,还是两端出发

(2)快指针:谁先动,满足某个条件,先动的是快

1.移动零

本题中:从同一端出发

快指针去找0,慢指针走非0的元素,找到0后,快慢指针交换元素

class Solution {
    public void moveZeroes(int[] nums) {
        int slow=0;
        for (int fast = 0; fast < nums.length; fast++) {
            if (nums[fast]!=0) {
                int mid =nums[fast];
                nums[fast]=nums[slow];
                nums[slow]=mid;
                slow++;
            }
        }
    }
}

2.盛最多水的容器

体积等于 高*底长

移动两端小的数的指针,减少底长,高不变。再比较移动后与移动前的体积大小。

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

3.三数之和

哈希解法

两层for循环就可以确定 a 和b 的数值了,可以使用哈希法来确定 0-(a+b) 是否在 数组里出现过,其实这个思路是正确的,但是我们有一个非常棘手的问题,就是题目中说的不可以包含重复的三元组。把符合条件的三元组放进vector中,然后再去重,这样是非常费时的,很容易超时,也是这道题目通过率如此之低的根源所在。

双指针解法

两层循环O(n2)。先对数组排序。

最外层循环i,从0开始。内层循环,左右两个指针left,right.如果i,left,right的和大于0,左移right,使3者的和变小。当left>=right结束内层循环。

快速创建List集合,并快速的添加元素

使用Arrays的asList()方法,直接返回一个集合

		List<String> stringList = Arrays.asList("张三", "李四", "王五");
        // 遍历集合
        stringList.forEach(name -> System.out.println(name));   // JDK8新特性

初始化添加元素

List<String> list = new ArrayList<String>(){
			{
				this.add("a");
				this.add("b");
				this.add("c");
			}
		};

class Solution {
    public List<List<Integer>> threeSum(int[] nums) {
        List<List<Integer>> set =new ArrayList<>();
        if(nums == null || nums.length < 3) return set;
        Arrays.sort(nums);
        for (int i = 0; i < nums.length; i++) {
            if(nums[i] > 0) break;
            // 如果当前数字大于0,则三数之和一定大于0,所以结束循环
            if(i > 0 && nums[i] == nums[i-1]) continue;
            // 去重,相邻重复的跳过找三数和的操作
            int left=i+1;
            int right=nums.length-1;
            while (left<right) {   
                int sum=nums[i]+nums[left]+nums[right];
                if (sum<0 ) {
                    left++;
                }else if (sum>0) {
                    right--;
                }else {
                    set.add(Arrays.asList(nums[i],nums[left],nums[right]));
                    while(left<right&&nums[left]==nums[left+1]) left++;//去重
                    while(left<right&&nums[right]==nums[right-1]) right--;//去重
                    //找到一组后,两边要同时移动,只移一边肯定不相等
                    left++;
                    right--;
                }
            }    
        }
        return set;
    }
}
//代码简写
if (sum<0 ) left++;
else if (sum>0) right--;

4.接雨水

给定 n 个非负整数表示每个宽度为 1 的柱子的高度图,计算按此排列的柱子,下雨之后能接多少雨水。

方法一:朴素解法

对每个元素,左边,右边搜素找最大值,再用二者间的最小值与当前元素做差,即为当前能接到的水。

class Solution {
    public int trap(int[] height) { 
        int V=0;
        for (int i = 1; i < height.length-1; i++) {
            int L_M=0;
            int R_M=0;
            for (int j = i-1; j >=0; j--) {
                L_M=Math.max(L_M, height[j]);
            }
            for (int j = i+1; j < height.length; j++) {
                R_M=Math.max(R_M, height[j]);
            }
            int Min_LR=Math.min(L_M, R_M);
            if (Min_LR>height[i]) {
                V=V+Min_LR-height[i];
            }
            
        }
        return V;
    }
}

方法二:双指针

遍历每个元素的同时,两边找最大值,计算该点处的蓄水量

class Solution {
    public int trap(int[] height) {
        int left=0; int right=height.length-1;
        int LMVal=0; int RMVal=0;
        int sum=0;
        while (left<=right) {
            if (height[left]<=height[right] ) { 
                //左边比右边小,从左边开始找
                LMVal=Math.max(LMVal, height[left]);
                sum+=LMVal-height[left];
                left++;
            }else{
                RMVal=Math.max(RMVal, height[right]);
                sum+=RMVal-height[right];
                right--;
            }
        }
        return sum;
    }
}

  • 8
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值