主旨:哈希表可以想象成一个数组,通常用来快速查询一个元素是否在集合中!通过将元素映射为哈希表上的索引,就可以通过索引快速定位该元素是否在集合中。
242. 有效的字母异位词
思路:题目仅包含小写字母,所以数组用26就够用了。
- 第一次for循环,将每个元素转为数值放到数组上,进行累加计算出现的次数
- 第二次for循环,将每个元素转为数值放到数组上,进行减法计算扣除出现的次数
- 最终for循环比较数组元素是否都为0,如果是表示相等!
public boolean isAnagram(String s, String t) {
int[] record=new int[26];
for(char ch : s.toCharArray()){
record[ch-'a']++;
}
for(char ch : t.toCharArray()){
record[ch-'a']--;
}
for(int i=0;i<record.length;i++){
if(record[i]!=0){
return false;
}
}
return true;
}
相关题目:383. 赎金信
思路:基本一样,只是这里变成记录magazine中的字母次数
public boolean canConstruct(String ransomNote, String magazine) {
int[] record=new int[26];
for(char ch:magazine.toCharArray()){
record[ch-'a']++;
}
for(char ch : ransomNote.toCharArray()){
if(record[ch-'a']>0)
record[ch-'a']--;
else
return false;
}
return true;
}
相关题目:49. 字母异位词分组
思路:
- 用map先存放目前的集合!最后再转换一下
key为字符串重新排序后的样子,value为List集合。- 为什么map?因为key是不可重复的。
- 遍历元素,将当前元素重新排序
- 排序后的元素是否存在map中
- 如果无则新建集合作为value,放入集合中
- 如果有则取出值,把当前原本的元素放入集合中
public List<List<String>> groupAnagrams(String[] strs) {
Map<String,List<String>> map=new HashMap<>();
for(int i=0;i<strs.length;i++){
char[] chs=strs[i].toCharArray();
Arrays.sort(chs);
String s=String.valueOf(chs);
if(!map.containsKey(s)){
map.put(s,new ArrayList<>());
}
map.get(s).add(strs[i]);
}
return new ArrayList<>(map.values());
}
相关题目:438. 找到字符串中所有字母异位词
思路:主要利用两个数组来实现,record记录p所有字母次数,window进行移动(它有点类似滑动窗口的概念)
left指针记录起始位置- 遍历元素,
window记录当前元素 - 当目前字符串长度
(i-left+1)等于p长度时,进行检查- 如果两个数组相等则表示找到了加入到
list中 - 不管有无,
window中left指针指向的元素次数减一,并且left指针要往前移动
- 如果两个数组相等则表示找到了加入到
public List<Integer> findAnagrams(String s, String p) {
List<Integer> list=new ArrayList<>();
int[] record=new int[26];
for(char ch : p.toCharArray()){
record[ch-'a']++;
}
int[] window=new int[26];
int left=0;
for(int i=0;i<s.length();i++){
window[s.charAt(i)-'a']++;
if(i-left+1==p.length()){
if(Arrays.equals(record,window)){
list.add(left);
}
window[s.charAt(left)-'a']--;
left++;
}
}
return list;
}
349. 两个数组的交集
思路:答案不需要重复,所以可以用set先暂存结果,最后转为题目要的类型 使用java8特性的stream流,将集合转为另一个集合
Stream的mapToInt(ToIntFunction mapper)返回一个IntStream流IntStream的toArray()返回一个包含此流元素的数组
public int[] intersection(int[] nums1, int[] nums2) {
if(nums1==null || nums1.length==0 || nums2==null || nums2.length==0)
return new int[2];
Set<Integer> set=new HashSet<>();
Set<Integer> resSet=new HashSet<>(); //暂存结果
for(int i: nums1){
set.add(i);
}
for(int i:nums2){
if(set.contains(i)){
resSet.add(i);
}
}
return resSet.stream()
.mapToInt(x->x) //返回IntStream
.toArray(); //IntStream.toArray()
}
202. 快乐数
思路:用set记录计算过的数字,如果当前元素在set中存在,表示是曾经计算过的数字,则陷入循环无解。最后判断一下是否为1
public boolean isHappy(int n) {
Set<Integer> set=new HashSet<>(); //记录出现过的数字
while(n!=1 && !set.contains(n)){
set.add(n);
n=nextNumber(n);
}
return n==1;
}
public int nextNumber(int n){
int res=0;
while(n>0){
int tmp=n%10;
res+=tmp*tmp;
n=n/10;
}
return res;
}
1. 两数之和
思路:要记住位置又要记住值,所以用map合适,值为key,下标为value。记得每次遍历都将当前元素放入集合中。
public int[] twoSum(int[] nums, int target) {
Map<Integer,Integer> map=new HashMap<>();
for(int i=0;i<nums.length;i++){
int sum=target-nums[i];
if(map.containsKey(sum)){
int[] res=new int[]{map.get(sum),i};
return res;
}
map.put(nums[i],i);
}
return new int[2];
}
454. 四数相加 II
思路:分为abcd,现在要a+b+c+d=0,两个为一组,(a+b)+(c+d)=0推导得到(a+b)=0-(c+d)
- 先把
(a+b)放到map集合中,value记录等于该值的次数 - 计算
0-(c+d),如果集合中有符合的,则表示找到一组符合条件的四数相加,取出value累加
public int fourSumCount(int[] nums1, int[] nums2, int[] nums3, int[] nums4) {
int res=0;
Map<Integer,Integer> map=new HashMap<>();
for(int a:nums1){
for(int b:nums2){
map.put(a+b,map.getOrDefault(a+b,0)+1);
}
}
for(int c:nums3){
for(int d:nums4){
int sum=0-(c+d);
if(map.containsKey(sum)){
res+=map.get(sum);
}
}
}
return res;
}
15. 三数之和
思路: 不可以包含重复的三元组,所以数组要先进行排序,然后每次遍历都要进行判断当前元素之前是否出现过,有则跳过!
- 找到第一个元素后,接下来用双向指针指向当前元素的下一个,和数组结尾元素
- 记得找到符合的三元组后,指针都要移动,此时指针注意:
- 不能超出移动范围
- 并且要判断下一个元素是否重复(有则要跳过)
public List<List<Integer>> threeSum(int[] nums) {
List<List<Integer>> list=new ArrayList<>();
if(nums.length<3)
return list;
Arrays.sort(nums);
for(int i=0;i<nums.length;i++){
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){
right--;
}else if(sum<0){
left++;
}
else{
list.add(new ArrayList<>(Arrays.asList(nums[i],nums[left],nums[right])));
while(left<right && nums[left]==nums[left+1])
left++;
while(left<right && nums[right-1]==nums[right])
right--;
left++;
right--;
}
}
}
return list;
}
18. 四数之和
思路:和上面的三数之和差不多,第二个选取的元素只要重复第一个选取的步骤即可
public List<List<Integer>> fourSum(int[] nums, int target) {
List<List<Integer>> list=new ArrayList<>();
Arrays.sort(nums);
for(int i=0;i<nums.length;i++){
//找第一个元素
if(i>0 && nums[i]==nums[i-1])
continue;
for(int j=i+1;j<nums.length;j++){
//找第二个元素
if(j>i+1 && nums[j]==nums[j-1])
continue;
//找第三和四个元素
int left=j+1;
int right=nums.length-1;
while(left<right){
long sum=(long)nums[i]+nums[j]+nums[left]+nums[right];
if(sum>target){
right--;
}else if(sum<target)
left++;
else{
list.add(Arrays.asList(nums[i],nums[j],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 list;
}