java算法day29

java算法day29

  • 128 最长连续序列
  • 3 无重复字符的最长子串
  • 11 盛最多水的容器
  • 49 字母异位词分组

128 最长连续序列

这个题审好题是关键。
这个题问的最长连续序列指的是数字依次递增的序列的最长长度。
比如例子[100,4,200,1,3,2]
那么就是1,2,3,4。长度为4
[0,3,7,2,5,8,4,6,0,1]
那么就是0,1,2,3,4,5,6,7,8长度为9

接下来来看做法:
这个题最好想的应该是哈希。最直观的想法应该就是为了统计每个连续序列的长度,那么我们希望定位到每个连续序列的起点。然后从起点开始遍历每个序列,从而获取长度,更新最长长度。

问题关键:什么样的数才是一个连续序列的起点?
回答是这个数的前一个数不存在于数组中。因此我们需要能够快速判断当前num的前num-1是否存在于数组中。那么快速判断我们就可以用哈希来优化。如果num-1还在数组中,那说明这个num肯定不是序列的起点,如果不在数组中,那么就能肯定,是序列的起点。至于为什么,自己想想就清楚了。

那么定位到了起点之后,就要从起点开始遍历整个序列,直到当前数的num+1并不存在于数组中时,可以判断遍历终止,因此还需要能够快速判断num后面的num+1是否存在于数组中。

可以看到这个过程涉及了很多快速查找的使用,因此哈希表用来存储数组中的所有数已经非常明确了。

class Solution {
    public int longestConsecutive(int[] nums) {
        int res = 0;    // 记录最长连续序列的长度
        Set<Integer> numSet = new HashSet<>();  // 记录所有的数值
        for(int num: nums){
            numSet.add(num);    // 将数组中的值加入哈希表中
        }
        int seqLen = 0;     // 连续序列的长度
        for(int num: numSet){
            // 如果当前的数是一个连续序列的起点,统计这个连续序列的长度
            if(!numSet.contains(num - 1)){
                seqLen = 1;
                while(numSet.contains(++num))seqLen++;  // 不断查找连续序列,直到num的下一个数不存在于数组中
                res = Math.max(res, seqLen);    // 更新最长连续序列长度
            }
        }
        return res;
    }
}


3 无重复字符的最长子串

循环+哈希(应该是暴力解法)

遍历每个字符,以每个字符为起点往后搜索,用hash判断是否在表中来判断是否出现重复字符。往后不断搜索来迭代最大值。一旦出现重复字符,那么一次往后搜索结束。
就是这样对每个字符进行处理

class Solution {
    public int lengthOfLongestSubstring(String s) {
        char[] str = s.toCharArray();
        Map<Character,Boolean> map = new HashMap<>();
        int maxLen = Integer.MIN_VALUE;
        int strLen = str.length;
        if(strLen==0){
            return 0;
        }
		//遍历每个字符
        for(int i = 0;i<strLen;i++){
            int tempLen = 0;
            int j = i;
            //从当前字符往后搜索,用hash来进行快速判断是否重复
            while(j<strLen && map.containsKey(str[j])==false){
                tempLen++;
                map.put(str[j],true);
                j++;
            }
            //遇到重复,循环结束。
            //更新最大值,然后清空map重新统计
            maxLen = Math.max(maxLen,tempLen);
            map.clear();
        }
        return maxLen;
    }
}

11 盛最多水的容器

这个题简单想就是两个for,维护一个最大值就完事了。但是暴力时间超限了。

贪心搜索

盛最多的水,那么可以类比为面积。那么很简单就能得到面积公式:
s(i,j) = min(h[i],h[j]) × (j-i)
从上面公式来看,面积取决于两挡板中的短板,还有一个就是底边长度。
在这里插入图片描述

搜索迭代的方式如下:

在每个状态下,无论长板或短板向中间收窄一格,都会导致水槽 底边宽度 −1​ 变短:

若向内 移动短板 ,水槽的短板 min(h[i],h[j]) 可能变大,因此下个水槽的面积 可能增大
若向内 移动长板 ,水槽的短板 min(h[i],h[j])​ 不变或变小,因此下个水槽的面积 一定变小

因此更新的策略就是:
双指针分别指向两端的挡板,每轮循环将短板向内移动,并维护面积最大值,直到两指针相遇时跳出,即可获得最大面积。

这是我第一次写的代码:

class Solution {
    public int maxArea(int[] height) {
        int i  = 0;
        int j = height.length-1;
        int res = 0;
        //双指针算法,当两挡板相遇就停下来,不用写等于,因为等于没意义。
        while(i<j){
        //都是对短板的判断,谁短移动谁
            if(height[i]<height[j]){
            //移动之前先迭代,迭代之后移动到下一个状态
                res = Math.max(res,(j-i)*Math.min(height[i],height[j]));
                i++;
            }else{
                res = Math.max(res,(j-i)*Math.min(height[i],height[j]));
                j--;
            }
        }
        return res;
    }
}

基本上的思路就是两变短板比较,计算当前面积,迭代最大值,然后移动短板。

还有优化一点的写法,写法上进行优化:

class Solution {
    public int maxArea(int[] height) {
        int i = 0, j = height.length - 1, res = 0;
        while(i < j) {
            res = height[i] < height[j] ? 
                Math.max(res, (j - i) * height[i++]): 
                Math.max(res, (j - i) * height[j--]); 
        }
        return res;
    }
}

这个写法和我上面的区别不大,就是写法上简化了if判断和i++或者j–写入到下标中


49 字母异位词分组

做法:排序加哈希
通过这个题,学习到了如何判断是字母异位词的方法。
判断是异位词的方法就是 排序!

如果某几个字符串是字母异位词,那么如何判断他们是同一种异位词的方法就是排序,他们排序过后得到的字符串是一样的。所以这里再配合HashMap。对每个str进行排序后就得到了该字符串的key,HashMap添加key和value即可。

class Solution {
    public List<List<String>> groupAnagrams(String[] strs) {
            Map<String,List<String>> map = new HashMap<>();
            for(String str : strs){
                //先获取key
                char[] strArray = str.toCharArray();
                //然后对当前字符数组排序
                Arrays.sort(strArray);
                //得到map的key
                String key = String.valueOf(strArray);
                //然后获取对应key的列表
                List<String> curStrList = map.get(key);
                if(curStrList==null){
                //此时curStrList是null,那么不能单纯的new一个放进map,必须要curStrList = new ArrayList<>();,否则下面代码.add空指针了。
                    curStrList = new ArrayList<>();
                    //把这个拿出来的联表又放回去
                    map.put(key,curStrList);
                }
                //把当前字符串放入这个拿出来的联表,然后放回去
                curStrList.add(str);
                map.put(key,curStrList);

            }

            List<List<String>> result = new ArrayList<>();
            for(Map.Entry<String,List<String>> entry : map.entrySet()){
                List<String> templList = entry.getValue();
                result.add(templList);
            }
            return result;
            
    }
}

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

1、判断字母异味词的方法+遍历判断子串。
就是纯暴力解

class Solution {
    public List<Integer> findAnagrams(String s, String p) {
        char[] tempKey = p.toCharArray();
        int length = tempKey.length;
        Arrays.sort(tempKey);
        //获取key
        String key = String.valueOf(tempKey);
        Map<String,Boolean> map = new HashMap<>();
        map.put(key,true);
        List<Integer> result = new ArrayList<>();

        //开始遍历
        for(int i = 0;i<=s.length()-length;i++){
            String tempCompare = s.substring(i,i+length);
            char[] tempCompareArray = tempCompare.toCharArray();
            Arrays.sort(tempCompareArray);
            String realCompare = String.valueOf(tempCompareArray);
            if(map.containsKey(realCompare)){
                result.add(i);
            }
        }

        return result;
    }
}
  • 4
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值