leetcode--哈希表概念总结和经典题目解析

目录

题目一:变位词组

题目二:两数之和

题目三:数对和

题目四:有效的字母异位词

题目五:有多少个数字相当于当前数字

题目六:森林中的兔子

题目七:根据字符出现频率排序


哈希表

    主要利用hashmap的键值对特点,进行数据的处理。

个人总结的一段常用代码:

map中某个键对应的值需要改变+1的时候,先取出该键对应的值,再把该值加1之后重新放入map中。

if(map.containsKey(key1)){
    int tempcount = map.get(keys)+1;
    map.put(key1,tempcount);
}

题目一:变位词组

(题目链接:https://leetcode-cn.com/problems/group-anagrams-lcci)

编写一种方法,对字符串数组进行排序,将所有变位词组合在一起。变位词是指字母相同,但排列不同的字符串。

注意:本题相对原题稍作修改

示例:

输入: ["eat", "tea", "tan", "ate", "nat", "bat"],
输出:
[
  ["ate","eat","tea"],
  ["nat","tan"],
  ["bat"]
]
说明:

所有输入均为小写字母。
不考虑答案输出的顺序。

方法:使用hashmap存储结构进行数据的存储,其中key存的字符串包含字母相同并且也顺序相同的,value存储的包含字母相同但是也顺序不同的

Java源代码

import java.util.*;

public class hashword {
    public static void main(String[] args) {
        String[] strs = new String[]{"eat", "tea", "tan", "ate", "nat", "bat"};
        List<List<String>> strs2 = new ArrayList<List<String>>();
        Map<String, List<String>> map = new HashMap<String, List<String>>();
        for (int i = 0; i <strs.length ; i++) {
            char[] arr = strs[i].toCharArray();
            Arrays.sort(arr);
            String arrstr = new String(arr);
            if(!map.containsKey(arrstr)){
                List<String> templiststring = new ArrayList<>();
                templiststring.add(strs[i]);
                map.put(arrstr,templiststring);
            }
            else{
                map.get(arrstr).add(strs[i]);
            }
        }
        for(String key :map.keySet()){
            strs2.add(map.get(key));
        }
        System.out.println("value: "+strs2);
    }
}

最重要的步骤:

    记得对要处理的字符串转换为字符数组,然后对字符数组进行排序。

【注意】:思路总结:新的哈希结构HashMap<String, List<String>>();注意,这是我之前没有的思维,即map中key和value传统是一一对应的,

但是我们把value的数据结构形式定位list<String>,这样实质上实现了一对多的存储,此种哈希思维注意总结

【注意】:语法总结:把字符数组变为字符串,我们使用String arrstr = new String(arr);

                                    把字符串变成字符数组,我们使用char[] arr = str.toCharArray();

【注意】:语法总结:Arrays.sort(arr)可以实现数组的自动排序

题目二:两数之和

(题目链接:https://leetcode-cn.com/problems/two-sum

给定一个整数数组 nums 和一个整数目标值 target,请你在该数组中找出 和为目标值 的那 两个 整数,并返回它们的数组下标。

你可以假设每种输入只会对应一个答案。但是,数组中同一个元素不能使用两遍。

你可以按任意顺序返回答案。

示例 1:

输入:nums = [2,7,11,15], target = 9
输出:[0,1]
解释:因为 nums[0] + nums[1] == 9 ,返回 [0, 1] 。
示例 2:

输入:nums = [3,2,4], target = 6
输出:[1,2]
示例 3:

输入:nums = [3,3], target = 6
输出:[0,1]

方法一:直接for循环,比较简单,我们不在展示代码

方法二:此处主要讲解使用哈希的方法解题

官方思路:使用hash表来存储数组的值和数组的索引:数组的值对应与hashtable的key,数组的索引对应hashtable的value。

    通过一个for循环,判断target-nums[i]是否在hashtable中,如果在,则找到了,返回结果即可,如果不在,则把num[i],和i存储到hashtable中。

Java源代码

import java.util.HashMap;
import java.util.Map;

public class twocount_sum {
    public static void main(String[] args) {
        int[] nums = new int[]{2,6,7,15};
        int target = 9;
        int result[] = new int[2];
        Map<Integer,Integer> hashtable = new HashMap<Integer,Integer>();
        for (int i = 0; i < nums.length; i++) {
            if(hashtable.containsKey(target - nums[i])){
                result[0] = i ;
                result[1] = hashtable.get(target-nums[i]);
            }else{
                hashtable.put(nums[i], i);
            }

        }
        for (int i = 0; i < 2; i++) {
            System.out.println(result[i]);
        }
    }
}

 第二次写的代码:

import java.util.*;


public class Solution {
    /**
     * 
     * @param numbers int整型一维数组 
     * @param target int整型 
     * @return int整型一维数组
     */
    public int[] twoSum (int[] numbers, int target) {
        // write code here
        int[] res = new int[2];
        Map<Integer,Integer> map = new HashMap<Integer,Integer>();
        for(int i =0;i<numbers.length;i++){
            map.put(numbers[i],i+1);
        }
        for(int i =0;i<numbers.length;i++){
            
            if(map.containsKey(target - numbers[i])){
                if( (i+1) != map.get(target - numbers[i])){
                    res[0] = i+1;
                res[1] = map.get(target-numbers[i]);
                break;
                }
                
            }
        }
        return res;
    }
}

题目三:数对和

(题目链接:https://leetcode-cn.com/problems/pairs-with-sum-lcci/)

设计一个算法,找出数组中两数之和为指定值的所有整数对。一个数只能属于一个数对。

示例 1:

输入: nums = [5,6,5], target = 11
输出: [[5,6]]
示例 2:

输入: nums = [5,6,5,6], target = 11
输出: [[5,6],[5,6]]

思路:利用hashtable进行数组中元素存储

官方:后续研究一下官方的简洁代码

Java源代码:

class Solution {
    public List<List<Integer>> pairSums(int[] nums, int target) {
        List<List<Integer>> res = new ArrayList<List<Integer>>();
        Map<Integer,Integer> map1 = new HashMap<Integer, Integer>();
        for (int i = 0; i < nums.length; i++) {
            if(map1.containsKey(nums[i])){
                int tempcount = map1.get(nums[i]) +1;
                map1.put(nums[i] , tempcount);
            }else{
                map1.put(nums[i],1);
            }
        }
        for (int i = 0; i < nums.length; i++) {
            if(map1.containsKey(target- nums[i]) ){
                if(map1.get(target - nums[i]) >0){
                    
                    //System.out.println("first: "+nums[i]+" second: "+(int)(target- nums[i]));
                    int tempcount2 = map1.get(target - nums[i])-1;
                    map1.put( target - nums[i],tempcount2);
                    if(map1.get(nums[i]) >0){
                        List<Integer> tempres = new ArrayList<Integer>();
                    tempres.add(nums[i]);
                    tempres.add((int)(target- nums[i]));
                    res.add(tempres);
                    }
                    int tempcount3 = map1.get(nums[i])-1;
                    map1.put(nums[i],tempcount3);
                }
            }

        }
        return res;
    }
}

题目四:有效的字母异位词

(题目链接:https://leetcode-cn.com/problems/valid-anagram/

给定两个字符串 s 和 t ,编写一个函数来判断 t 是否是 s 的字母异位词。

示例 1:

输入: s = "anagram", t = "nagaram"
输出: true
示例 2:

输入: s = "rat", t = "car"
输出: false

方法一:把字符串变成字符数组,对字符数组排序,排序后的字符数组变成字符串,判断两个字符串是否相等

Java源代码:

class Solution {
    public boolean isAnagram(String s, String t) {
        char[] chars = s.toCharArray();
        Arrays.sort(chars);
        char[] chart = t.toCharArray();
        Arrays.sort(chart);
        if(Arrays.toString(chars).equals(Arrays.toString(chart))){
            return true;
        }else {
            return false;
        }
    }
}

方法二:采用一个数组,判断每个字符出现的次数。

         官方方法:遍历第一个字符串,出现某个字符,则出现次数加1,遍历第二个字符串,出现某个字符,则统计好的次数减1

class Solution {
    public boolean isAnagram(String s, String t) {
        int[] table = new int[26];
        for (int i = 0; i < s.length(); i++) {
            table[s.charAt(i)-'a']++;
        }
        for (int i = 0; i < t.length(); i++) {
            table[t.charAt(i)-'a']--;
        }
        for (int i = 0; i < 26; i++) {
            if(table[i]!=0){
                return false;
            }
        }
        return true;
    }
}

 第二次写的代码

class Solution {
    public boolean isAnagram(String s, String t) {
        Map<Character,Integer> map = new HashMap<Character,Integer>();
        int slength = s.length();
        int tlength = t.length();
        if(slength != tlength){
            return false;
        }else{
            for(int i =0;i<slength;i++){
                if(map.containsKey(s.charAt(i))){
                    int tempcount = map.get(s.charAt(i))+1;
                    map.put(s.charAt(i),tempcount);
                }else{
                    map.put(s.charAt(i),1);
                }
            }
           for(int j =0;j<tlength;j++){
               if(map.containsKey(t.charAt(j))){
                   int tempcount2 = map.get(t.charAt(j))-1;
                   map.put(t.charAt(j),tempcount2);
               }else{
                   return false;
               }
           }
           for(char key:map.keySet()){
               if(map.get(key)!=0){
                   return false;
               }
           }
           return true;
        }
    }
}

题目五:有多少个数字相当于当前数字

(题目链接:https://leetcode-cn.com/problems/how-many-numbers-are-smaller-than-the-current-number/

给你一个数组 nums,对于其中每个元素 nums[i],请你统计数组中比它小的所有数字的数目。

换而言之,对于每个 nums[i] 你必须计算出有效的 j 的数量,其中 j 满足 j != i 且 nums[j] < nums[i] 。

以数组形式返回答案。

示例 1:

输入:nums = [8,1,2,2,3]
输出:[4,0,1,1,3]
解释: 
对于 nums[0]=8 存在四个比它小的数字:(1,2,2 和 3)。 
对于 nums[1]=1 不存在比它小的数字。
对于 nums[2]=2 存在一个比它小的数字:(1)。 
对于 nums[3]=2 存在一个比它小的数字:(1)。 
对于 nums[4]=3 存在三个比它小的数字:(1,2 和 2)。

思路:直接两重for循环,暴力法解决

class Solution {
    public int[] smallerNumbersThanCurrent(int[] nums) {
        int[] res = new int[nums.length];
        for(int i =0;i<res.length;i++){
            res[i]=0;
        }
        for(int i =0; i< nums.length;i++){
            for(int j =0; j<nums.length;j++){
                if(nums[i]>nums[j]){
                    res[i]++;
                }
            }
        }
        return res;
    }
}

题目六:森林中的兔子

链接:https://leetcode-cn.com/problems/rabbits-in-forest

森林中,每个兔子都有颜色。其中一些兔子(可能是全部)告诉你还有多少其他的兔子和自己有相同的颜色。我们将这些回答放在 answers 数组里。

返回森林中兔子的最少数量。

示例:
输入: answers = [1, 1, 2]
输出: 5
解释:
两只回答了 "1" 的兔子可能有相同的颜色,设为红色。
之后回答了 "2" 的兔子不会是红色,否则他们的回答会相互矛盾。
设回答了 "2" 的兔子为蓝色。
此外,森林中还应有另外 2 只蓝色兔子的回答没有包含在数组中。
因此森林中兔子的最少数量是 5: 3 只回答的和 2 只没有回答的。

输入: answers = [10, 10, 10]
输出: 11

输入: answers = []
输出: 0

思路:主要找到逻辑的关键:

假设回答 k 的兔子的数量为 v = count[k],通过上面分析可以知道至少有 a 只兔子,其中 a 是满足 a >= count[k] 的最小 k + 1 的倍数。

class Solution {
    public int numRabbits(int[] answers) {
        int res = 0;
        Map<Integer,Integer> hashtable = new HashMap<Integer,Integer>();
        for (int i = 0; i <answers.length ; i++) {
            if(hashtable.containsKey(answers[i])){
                int temp = hashtable.get(answers[i])+1;
                hashtable.put(answers[i],temp);
            }else{
                hashtable.put(answers[i],1);
            }
        }
        for (int key : hashtable.keySet()){
            for(int i =1; ;i++){
                int curr = (key+1)*i;
                if(curr >= hashtable.get(key)){
                    res = res + curr;
                    break;
                }
            }
        }
        return res;
    }
}

题目七:根据字符出现频率排序

(链接:https://leetcode-cn.com/problems/sort-characters-by-frequency/)

给定一个字符串,请将字符串里的字符按照出现的频率降序排列。

示例 1:

输入:
"tree"

输出:
"eert"

解释:
'e'出现两次,'r'和't'都只出现一次。
因此'e'必须出现在'r'和't'之前。此外,"eetr"也是一个有效的答案。

思路:采用hash表存储各个字符及它们出现的频率,根据hash表的value进行大小排序,进行输出

class Solution {
    public String frequencySort(String s) {
        Map<Character,Integer> hashtable = new HashMap<Character,Integer>();
        for (int i = 0; i < s.length(); i++) {
            char curr = s.charAt(i);
            if(hashtable.containsKey(curr)){
                int currcount=hashtable.get(curr)+1;
                hashtable.put(curr,currcount);
            }else{
                hashtable.put(curr,1);
            }
        }
        int[] value = new int[hashtable.size()];
        int i = 0;
        char[] key = new char[hashtable.size()];
        int j =0;
        for(Character keyi: hashtable.keySet()){
            value[i++] = hashtable.get(keyi);
            key[j++] = keyi;
        }
        //System.out.println(Arrays.toString(key));
        //System.out.println(Arrays.toString(value));
        for (int k = 0; k < value.length-1; k++) {
            for (int l = 0; l < value.length-k-1; l++) {
                if(value[l] < value[l+1]){
                    int temp = value[l];
                    value[l] = value[l+1];
                    value[l+1] = temp;
                    char temp2 = key[l];
                    key[l] = key[l+1];
                    key[l+1] = temp2;
                }
            }
        }
        String res="";
        for (int k = 0; k < key.length; k++) {
            for (int l = 0; l < value[k]; l++) {
                res += key[k];
            }
        }
        return res;
    }
}

猜你喜欢

转载自blog.csdn.net/yezonghui/article/details/112102687