496. Next Greater Element I+附hashmap用法

来源:互联网 发布:淘宝职业女装红色裙子 编辑:程序博客网 时间:2024/06/04 20:47

You are given two arrays (without duplicates) nums1 and nums2 where nums1’s elements are subset of nums2. Find all the next greater numbers for nums1's elements in the corresponding places of nums2.

The Next Greater Number of a number x in nums1 is the first greater number to its right in nums2. If it does not exist, output -1 for this number.

Example 1:

Input: nums1 = [4,1,2], nums2 = [1,3,4,2].Output: [-1,3,-1]Explanation:    For number 4 in the first array, you cannot find the next greater number for it in the second array, so output -1.    For number 1 in the first array, the next greater number for it in the second array is 3.    For number 2 in the first array, there is no next greater number for it in the second array, so output -1.

Example 2:

Input: nums1 = [2,4], nums2 = [1,2,3,4].Output: [3,-1]Explanation:    For number 2 in the first array, the next greater number for it in the second array is 3.    For number 4 in the first array, there is no next greater number for it in the second array, so output -1.

Note:

  1. All elements in nums1 and nums2 are unique.
  2. The length of both nums1 and nums2 would not exceed 1000.
public class Solution {    public int[] nextGreaterElement(int[] findNums, int[] nums) {        Map<Integer,Integer> m=new HashMap<>();        for(int i=0;i<nums.length;i++)        {            for(int j=i+1;j<nums.length;j++)            {                if(nums[i]<nums[j])                {                    m.put(nums[i],nums[j]);                    break;                }            }        }        for(int i=0;i<findNums.length;i++)        {            findNums[i]=m.getOrDefault(findNums[i],-1);        }           return findNums;     }}
读懂题很重要,一开始理解错了,所以怎么做都是错,附hashmap用法



Java中HashMap详解

HashMap 和 HashSet 是 Java Collection Framework 的两个重要成员,其中 HashMap 是 Map 接口的常用实现类,HashSet 是 Set 接口的常用实现类。虽然 HashMap 和 HashSet 实现的接口规范不同,但它们底层的 Hash 存储机制完全一样,甚至 HashSet 本身就采用 HashMap 来实现的。 

通过 HashMap、HashSet 的源代码分析其 Hash 存储机制


实际上,HashSet 和 HashMap 之间有很多相似之处,对于 HashSet 而言,系统采用 Hash 算法决定集合元素的存储位置,这样可以保证能快速存、取集合元素;对于 HashMap 而言,系统 key-value 当成一个整体进行处理,系统总是根据 Hash 算法来计算 key-value 的存储位置,这样可以保证能快速存、取 Map 的 key-value 对。 

在介绍集合存储之前需要指出一点:虽然集合号称存储的是 Java 对象,但实际上并不会真正将 Java 对象放入 Set 集合中,只是在 Set 集合中保留这些对象的引用而言。也就是说:Java 集合实际上是多个引用变量所组成的集合,这些引用变量指向实际的 Java 对象。 

集合和引用 

就像引用类型的数组一样,当我们把 Java 对象放入数组之时,并不是真正的把 Java 对象放入数组中,只是把对象的引用放入数组中,每个数组元素都是一个引用变量。 

HashMap 的存储实现


当程序试图将多个 key-value 放入 HashMap 中时,以如下代码片段为例:


HashMap<String , Double> map = new HashMap<String , Double>();   map.put("语文" , 80.0);   map.put("数学" , 89.0);   map.put("英语" , 78.2);   

HashMap 采用一种所谓的“Hash 算法”来决定每个元素的存储位置。 

当程序执行 map.put("语文" , 80.0); 时,系统将调用"语文"的 hashCode() 方法得到其 hashCode 值——每个 Java 对象都有 hashCode() 方法,都可通过该方法获得它的 hashCode 值。得到这个对象的 hashCode 值之后,系统会根据该 hashCode 值来决定该元素的存储位置。 

我们可以看 HashMap 类的 put(K key , V value) 方法的源代码:

public V put(K key, V value)   {    // 如果 key 为 null,调用 putForNullKey 方法进行处理   if (key == null)        return putForNullKey(value);    // 根据 key 的 keyCode 计算 Hash 值   int hash = hash(key.hashCode());    // 搜索指定 hash 值在对应 table 中的索引       int i = indexFor(hash, table.length);   // 如果 i 索引处的 Entry 不为 null,通过循环不断遍历 e 元素的下一个元素   for (Entry<K,V> e = table[i]; e != null; e = e.next)    {        Object k;        // 找到指定 key 与需要放入的 key 相等(hash 值相同       // 通过 equals 比较放回 true)       if (e.hash == hash && ((k = e.key) == key            || key.equals(k)))        {            V oldValue = e.value;            e.value = value;            e.recordAccess(this);            return oldValue;        }    }    // 如果 i 索引处的 Entry 为 null,表明此处还没有 Entry    modCount++;    // 将 key、value 添加到 i 索引处   addEntry(hash, key, value, i);    return null;   }   
上面程序中用到了一个重要的内部接口:Map.Entry,每个 Map.Entry 其实就是一个 key-value 对。从上面程序中可以看出:当系统决定存储 HashMap 中的 key-value 对时,完全没有考虑 Entry 中的 value,仅仅只是根据 key 来计算并决定每个 Entry 的存储位置。这也说明了前面的结论:我们完全可以把 Map 集合中的 value 当成 key 的附属,当系统决定了 key 的存储位置之后,value 随之保存在那里即可。 

上面方法提供了一个根据 hashCode() 返回值来计算 Hash 码的方法:hash(),这个方法是一个纯粹的数学计算,其方法如下: 
static int hash(int h)   {       h ^= (h >>> 20) ^ (h >>> 12);       return h ^ (h >>> 7) ^ (h >>> 4);   }   
对于任意给定的对象,只要它的 hashCode() 返回值相同,那么程序调用 hash(int h) 方法所计算得到的 Hash 码值总是相同的。接下来程序会调用 indexFor(int h, int length) 方法来计算该对象应该保存在 table 数组的哪个索引处。indexFor(int h, int length) 方法的代码如下:

static int indexFor(int h, int length)   {       return h & (length-1);   }  
这个方法非常巧妙,它总是通过 h &(table.length -1) 来得到该对象的保存位置——而 HashMap 底层数组的长度总是 2 的 n 次方,这一点可参看后面关于 HashMap 构造器的介绍。 

当 length 总是 2 的倍数时,h & (length-1) 将是一个非常巧妙的设计:假设 h=5,length=16, 那么 h & length - 1 将得到 5;如果 h=6,length=16, 那么 h & length - 1 将得到 6 ……如果 h=15,length=16, 那么 h & length - 1 将得到 15;但是当 h=16 时 , length=16 时,那么 h & length - 1 将得到 0 了;当 h=17 时 , length=16 时,那么 h & length - 1 将得到 1 了……这样保证计算得到的索引值总是位于 table 数组的索引之内。 

根据上面 put 方法的源代码可以看出,当程序试图将一个 key-value 对放入 HashMap 中时,程序首先根据该 key 的 hashCode() 返回值决定该 Entry 的存储位置:如果两个 Entry 的 key 的 hashCode() 返回值相同,那它们的存储位置相同。如果这两个 Entry 的 key 通过 equals 比较返回 true,新添加 Entry 的 value 将覆盖集合中原有 Entry 的 value,但 key 不会覆盖。如果这两个 Entry 的 key 通过 equals 比较返回 false,新添加的 Entry 将与集合中原有 Entry 形成 Entry 链,而且新添加的 Entry 位于 Entry 链的头部——具体说明继续看 addEntry() 方法的说明。 

当向 HashMap 中添加 key-value 对,由其 key 的 hashCode() 返回值决定该 key-value 对(就是 Entry 对象)的存储位置。当两个 Entry 对象的 key 的 hashCode() 返回值相同时,将由 key 通过 eqauls() 比较值决定是采用覆盖行为(返回 true),还是产生 Entry 链(返回 false)。 

上面程序中还调用了 addEntry(hash, key, value, i); 代码,其中 addEntry 是 HashMap 提供的一个包访问权限的方法,该方法仅用于添加一个 key-value 对。



原创粉丝点击