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;
}
}