LeetCode 热题100专题解析:哈希与双指针

本文将重点解析 LeetCode 热题100 中关于哈希和双指针的题目,帮助读者更好地理解和掌握这两种算法思想。

哈希表专题

  1. 两数之和

题目描述:给定一个整数数组和一个目标值,找出数组中 和 为目标值的两个数的下标。

上来的想法,想想人脑怎么着找。无非就是两层循环,那肯定有重复找的数的呀。我知道A他的天选就是B,那我不妨就把在找A的时候看看B好了,也省的非要凑齐A+B.

解题思路:这是一道典型的哈希表应用题目。我们可以遍历数组,对于每个元素,计算目标值与当前元素的差值,然后检查这个差值是否存在于已经遍历过的元素中。如果存在,那么我们就找到了一对和为目标值的数。

public int[] twoSum(int[] nums,int k){
	Map<Integer,Integer> map=new Hashmap<>();
	//题目让返回的是下标
	for(int i=0;i<nums.size();i++){
		if(map.containsKey(k-nums[i])){
			return new int[]{i,map.get(k-nums[i])};
		}
		map.put(nums[i],i);
	}
	return new int[]{-1,-1};
}

个人碎碎念:这道题也算是leetcode 热题100里面的 abandon了,我每次都从这个开始。也都abandon了。

  1. 字母异位词分组

题目描述:给定一个字符串数组,将字母异位词的字符串分组在一起。

异构词是什么, abc cba cab 《-这些就是异构词,它们构成的元素都是一样的,排列不同罢了。那就把他们打成一样的状态

解题思路:这个问题可以通过哈希表来解决。我们可以遍历每个字符串,计算它的字母频率(例如,‘a’ 出现的次数、‘b’ 出现的次数等),然后将这个频率作为键值存储在哈希表中。接着,对于每个新的字符串,我们检查它的字母频率是否已经存在于哈希表中,如果存在,就将它添加到对应的列表中。

伪代码
维护答案数组
遍历字符串数组
统计字符串次数 得到map
现在是以abc开头的,所以先往答案数组压入abc
之后根据abc的map进行判断,那些可以跟在abc的数组里面
如果他们统计次数都是和map里面的匹配,ok,加进去,然后从原来的数组里面remove掉。
java
public List<List> solution(String[] strs){
List<List> ans=new ArrayList<>();
维护这个结果,就考虑什么时候加就行了
那肯定是有元素和前面这个元素构成一样了呀,-》构成怎么表示-》hashmap
for(String str:strs){
HashMap<Character,Integer> map=new HashMap<>();
for(char c:str.toCharArray()){
map.put(c,map.getOrDefault(c,0)+1);
}
List tmp=new ArrayList<>();
tmp.add(str);
strs.remove(str);
for(String sameStr:strs){
写不下去了
}
}
}

上面是我错误思路下的产物。

我这里的错误就是没搞明白,hashmap保存的要是什么。
比较两个字符串元素,除了把他们拆开比较,一个一个存到map里面,一个个比较。还可以把他们排序之后equal比较。
其实在上面自己死胡同思路那里,就觉得hashmap应该是一个list,总不能用一个清空一个,那这后面的元素还怎么参考。


public List<List<String>> solution(String[] strs){
	Map<String,List<String>> map=new HashMap<>();
	for(String str:strs){
		//HashMap<Character,Integer> map=new HashMap<>();
		char[] array=str.toCharArray();
		Array.sort(array);
		String a=new String(array);
		if(!map.containsKey(a)){
			List<String> tmp=new ArrayList<>();
			tmp.add(str);
			map.put(a,tmp);
		}else{
			map.get(a).add(str);
		}
	}
	return new ArrayList<>(map.values());
}
  1. 最长连续序列

题目描述:给定一个整数数组,根据里面的元素 ,找出一个整数数组中最长连续序列的长度。要求时间复杂度O(n)

解题思路:这个问题可以通过使用哈希集合(HashSet)来高效地解决,时间复杂度可以达到O(n)。

  1. 创建一个哈希集合:用于存储数组中已经出现过的元素。

  2. 遍历数组:遍历给定的整数数组,对于数组中的每一个元素,执行以下操作:

    • 检查当前元素的前一个数(即当前元素减1)是否在哈希集合中。如果在,说明当前元素属于一个连续序列,可以更新最长序列的长度,并将前一个数加入到哈希集合中。
    • 如果当前元素不在哈希集合中,将其加入哈希集合。
  3. 更新最长序列长度:每次找到一个连续序列时,都需要检查这个序列的长度是否比当前记录的最长序列长度要长。如果是,则更新最长序列长度。

  4. 返回结果:遍历完成后,返回记录的最长序列长度。

以下是该算法的伪代码实现:

function findMaxLength(nums):
    max_length = 0
    seen = new HashSet()
    
    for num in nums:
        if num - 1 not in seen:
            current_length = 1
            while (num + 1) in seen:
                num += 1
                current_length += 1
            max_length = max(max_length, current_length)
        seen.add(num)
    
    return max_length

这个算法的时间复杂度是O(n),因为每个元素最多被访问两次:一次在主循环中,一次在while循环中(如果当前元素属于连续序列的话)。空间复杂度是O(n),因为哈希集合最多存储n个元素。

这种方法不需要对数组进行排序,也不需要额外的数组或列表来存储潜在的连续序列,因此它是一种非常高效的解决方案。

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

双指针专题

  1. 移动零

题目描述:给定一个数组,将所有 0 移动到数组的末尾,保持非零元素的相对顺序。

解题思路:这是一个经典的双指针问题。我们可以使用两个指针,一个指针遍历数组,另一个指针指向当前非零元素的位置。当我们遇到非零元素时,就将它与指针指向的位置交换,然后移动指针。

class Solution {
    public void moveZeroes(int[] nums) {
        int cur=0;
        for(int i=0;i<nums.length;i++){
            if(nums[i]!=0){
                nums[cur++]=nums[i];
            }
        }
        for(int i=cur;i<nums.length;i++){
            nums[i]=0;
        }
    }
}
  1. 盛最多水的容器

题目描述:给定一个由非负整数表示的数组,用来表示容器的宽度和高度。计算由这些容器组成的堤坝能盛多少水。

解题思路:这个问题可以通过双指针来解决。我们维护两个指针,一个在数组的开始,另一个在数组的末尾。这两个指针代表堤坝的两端。我们计算由这两个指针形成的堤坝能盛多少水,然后移动能形成更大堤坝的一端的指针。

class Solution {
    public int maxArea(int[] height) {
        int left = 0, right = height.length - 1;
        int ans = 0;
        while (left < right) {
            ans = Math.max(Math.min(height[right], height[left]) * (right - left), ans);
            if (height[left] < height[right])
                left++;
            else
                right--;
        }
        return ans;
    }
}
  1. 三数之和

题目描述:给定一个包含 n 个数字的数组,找出所有三元组,使得这些数的和为 0。

解题思路:虽然这个问题看起来需要三重循环,但实际上可以通过双指针技术来优化。首先对数组进行排序,然后遍历数组,对于每个元素,我们使用两个指针分别指向当前元素的左右两侧,尝试找到和为 0 的三元组。

  1. 接雨水

题目描述:给定 n 个非负整数,用以表示房屋的高度。如果雨水从上到下落下来,计算雨水能接多少。

解题思路:这个问题可以通过双指针和动态规划的结合来解决。我们维护一个数组来保存每个位置左边和右边的最高条形块。然后遍历原数组,计算每个位置能接的雨水量,即当前位置的房屋高度与左右两边最高条形块中的较小者之差。

  • 5
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值